Firefox Browser Add-ons
  • Extensions
  • Themes
    • for Firefox
    • Dictionaries & Language Packs
Log in
Add-on icon

F.B. Sponsored/Ad Post Blocker version history - 25 versions

F.B. Sponsored/Ad Post Blocker by Inky

Rated 4.8 out of 5
4.8 Stars out of 5
5
3
4
1
3
0
2
0
1
0
F.B. Sponsored/Ad Post Blocker version history - 25 versions
  • Be careful with old versions! These versions are displayed for testing and reference purposes.You should always use the latest version of an add-on.

  • Latest version

    Version 1.1.95

    Released Oct 28, 2026 - 118.72 KB
    Works with firefox 109.0 and later, android 120.0 and later
    • 1.1.94 could hide the whole News Feed behind one "Sponsored post hidden"
      bar.
      Its new check for "Ad" labels that arrive late could fire while
      Facebook was still laying the page out, when nothing on it had a size yet.
      The search for the rest of the post measures sizes to know where a post
      ends, so with everything at zero it kept going until it reached the whole
      feed column, stopping at the "What's on your mind?" box. It now stops
      where it is when nothing has a size, and the feed column itself can never
      be hidden as a post.


    92 automated tests pass. The new one reproduces the hidden feed on 1.1.94 —
    an "Ad" label connected while the feed column has no size — and passes on
    this build.

    Source code released under MIT License

    Download Firefox and get the extension
    Download file
  • Older versions

    Version 1.1.94

    Released Oct 27, 2026 - 118.22 KB
    Works with firefox 109.0 and later, android 120.0 and later
    • An ad from a Page your friends follow was credited to a friend. Such an
      ad opens with "Your friend and another friend follow …", and the extension
      took the first person linked in a post to be the poster. So the "Show"
      placeholder showed your friend's name instead of the advertiser's — and,
      worse, "Not an ad" put your friend on "Always show these Pages", and "This
      is an ad" put your friend on "Always treat these Pages as ads", after which
      their own posts linking off Facebook could be hidden. The poster is now the
      one named in the post's heading. If you used either button on such an ad,
      check "Your lists" in the popup for a friend's name and remove it.
    • Some ads labelled "Ad" stayed in the feed. Facebook sometimes connects
      a post to its "Ad" label seconds after the post appears — once, 20 seconds
      later. The extension only looked when the post first arrived, so unless
      another clue gave the ad away, it stayed. It now notices the label being
      connected. In a 14-minute scroll of a live feed, 3 of about 90 ads were
      missed this way.


    91 automated tests pass, five of them new. Three cover the placeholder's name
    and what each button records on an ad that opens with a friends line. Two
    cover a label connected late: the ad is hidden, and an ordinary post whose
    timestamp arrives the same way is not. The four ad tests fail on 1.1.93. On a
    live feed, 32 hidden posts were checked: two had been credited to a friend and
    now name the advertiser; the rest are unchanged.

    Source code released under MIT License

    Download file
  • Version 1.1.93

    Released Oct 26, 2026 - 117.13 KB
    Works with firefox 109.0 and later, android 120.0 and later
    • A safety net under every rule. Whichever rule finds an ad, the extension
      now refuses to hide anything that is, or holds, the page's main area, feed
      or navigation, or that is wider than a feed post on a computer. If the part
      it settled on is too big, it hides the post-sized card inside it around the
      label, or nothing. Both page-wide bugs so far — the right-hand column and
      Marketplace categories — would have been stopped by this alone. Suggested by
      a contributor in a fork of the project. Diagnostics counts what it refused.
    • Spanish, Portuguese, French, German, Indonesian, Arabic and Hungarian.
      The ad label in each language, read off a live feed with Facebook set to it,
      now counts — but only where Facebook puts the label, after the poster's
      name, so post text or a Page's name never does. Their Follow/Join buttons, Stories, Reels
      and People you may know headings, and how they write a post's age now work
      too; the last keeps real posts that share a link from being taken for ads.
      English is unchanged, except that its label is now read as "Sponsored ·" as
      well, the way Facebook writes it on some ads.


    86 automated tests pass, thirteen of them new: neither a wide page column nor
    the main page area is ever hidden, labels in English and other languages, a
    foreign ad word in post text, a Page name or Facebook's Hungarian footer link
    ignored, Hungarian's Follow button, and posts kept by their age in Spanish,
    Arabic and Hungarian. On a live English feed afterwards, ads were hidden as
    before and nothing wider than a post was. The test page no longer depends on
    being on screen to run scheduled scans.

    Source code released under MIT License

    Download file
  • Version 1.1.92

    Released Oct 20, 2026 - 113.66 KB
    Works with firefox 109.0 and later, android 120.0 and later
    • Marketplace categories showed nothing. Opening a category such as
      Vehicles left a single "Sponsored post hidden" bar where the listings should
      be. The results include sponsored tiles, and to hide one the extension
      looked for the post around it the way it does in the feed — outward until
      the page column — which on Marketplace is the whole grid of results. On
      Marketplace a sponsored tile is now hidden on its own, and the listings
      around it stay. The rules meant for feed posts (suggested posts, Pages you
      don't follow, ads Facebook doesn't label, feed sections) no longer run on
      Marketplace at all. Listings you open are left alone, as before.


    73 automated tests pass, two of them new: a sponsored tile hidden alone, and
    the listings beside it kept. The second fails on 1.1.91 exactly as reported.
    On a live Vehicles search, each sponsored tile resolved to that one tile and
    nothing else.

    Source code released under MIT License

    Download file
  • Version 1.1.91

    Released Oct 18, 2026 - 112.84 KB
    Works with firefox 109.0 and later, android 120.0 and later
    • Hidden-post placeholders say who the post is from. With "Display a
      'Show' button to reveal hidden posts" on, each placeholder now shows the
      name of the person, Page or Group under the reason it was hidden, so you
      can tell at a glance whether it should have been hidden without clicking
      Show. Group posts show the group and the member who posted. Long names are
      shortened, with the full name shown when you point at it. If Facebook has
      not filled in the name yet when the post is hidden, the placeholder looks
      again a moment later.
    • Some posts were hidden twice. Two rules could settle on different parts
      of the same post, so it counted twice towards "posts hidden", and a second
      placeholder sat inside it — clicking Show revealed the post with part of it
      still hidden behind another "post hidden" bar. Each post is now hidden once.


    71 automated tests pass, four of them new, and all four fail on 1.1.90: a
    Page's name read from its post heading rather than the "active" label on its
    profile picture, a group post naming both the group and the member, and one
    hide per post whichever part was hidden first. On a live feed every hidden
    post was named correctly.

    Source code released under MIT License

    Download file
  • Version 1.1.90

    Released Oct 17, 2026 - 110.91 KB
    Works with firefox 109.0 and later, android 120.0 and later
    • "This is NOT an ad". With the "This is an ad" buttons switched on, a
      second button now sits beside it over a post's picture. Clicking it puts the
      post's Page on "Always show these Pages", and from then on nothing hides that
      Page's posts no rule, not even a "Sponsored" label after reloads and on
      later visits too. The post you clicked is left alone straight away, even when
      its Page can't be worked out.
    • The two buttons now correct each other. "This is NOT an ad" takes the Page
      off "Always treat these Pages as ads", and "This is an ad" takes it off
      "Always show these Pages". Before, a Page could end up on both lists, where
      "always show" quietly won and the later click seemed to do nothing.
    • The buttons over pictures and the "Show" placeholders now match Facebook's
      own light or dark mode, whichever you have chosen there. In dark mode they
      were pale grey and hard to read.
    • On posts with several photos, the buttons appeared over the poster's name
      instead of the picture. Facebook draws those photos larger than their tile
      and crops the rest; the buttons now go by the part you can see.


    67 automated tests pass, four of them new, and each fails without its change:
    a Page marked "NOT an ad" stays visible after a reload even when its post is
    labelled Sponsored, each button takes the Page off the other list, and the
    buttons sit on the visible part of a cropped photo.

    Source code released under MIT License

    Download file
  • Version 1.1.89

    Released Sep 30, 2026 - 109.11 KB
    Works with firefox 109.0 and later, android 120.0 and later
    • Switches for Stories, Reels and People you may know. A new "Feed
      sections" group in the popup can hide any of them:
    • Stories — the row of stories at the top of the feed. The frame around
      it goes too, so no gap is left behind.
    • Reels — the Reels carousel in the feed.
    • People you may know — the friend-suggestions block in the feed.

    All three are off unless you turn them on, since none of them is an ad.
    Reels and People you may know are only hidden when the block really holds
    reels or friend suggestions, so a post or Page that merely has "Reels" in
    its title is left alone. A hidden section stays hidden when Facebook redraws
    it, and switching one back off brings it straight back.

    For now these work on a computer only; Facebook's phone site is built
    differently.


    63 automated tests pass, seven of them new: each section hidden when its
    switch is on and kept when it is off, a Page called "Reels" left alone, and a
    hidden section surviving a redraw. On a live feed, each rule picked out
    exactly its section and nothing else. The test page also runs correctly now
    when it is not on screen.

    Source code released under MIT License

    Download file
  • Version 1.1.88

    Released Sep 26, 2026 - 106.94 KB
    Works with firefox 109.0 and later, android 120.0 and later
    • The right-hand column no longer disappears with its ad. With "Hide
      Sponsored posts" on, the whole column went — Birthdays, Contacts and Group
      chats along with the sponsored block at its top. Facebook now wraps every
      section of that column in one element, which the extension took for the ad.
      It now stops at the next section's heading, so only the sponsored block goes.
    • "Show" on a hidden post now lasts. The next scan used to hide it again a
      moment later. A post you reveal stays revealed while it is on the page.
    • Every placeholder can keep its page. "Not an ad" (on sponsored posts) or
      "Always show" (on the rest) adds the page to your keep list, so its posts
      stay visible after a reload too. This used to be offered only for ads
      Facebook doesn't label. The keep list now applies to every rule, matched on
      who posted: an ad that merely tags a page on the list is still hidden.
    • An ad could come back and stay. Hidden posts are re-checked when they
      change, and if an ad's label was missing at that moment — a video player
      reloading, say — the ad was shown again and never looked at twice. It is now
      checked again one and three seconds later.
    • Ads hidden without a label (unlabelled ads, or ones you marked with "This is
      an ad") could flash back for up to half a second whenever something inside
      them changed. They now stay hidden.
    • A simpler popup. Settings are switches in two groups, "What to hide" and
      "While browsing", each with a short name and one plain line on what it does.
      The two page lists are folded into "Your lists", which shows how many pages
      they hold; the buttons on the page fill them in, so most people never need
      to open it. Follows the browser's dark mode. Every setting is unchanged.


    56 automated tests pass, seven of them new. Six fail on 1.1.87, so each
    catches the bug it was written for; the seventh checks that an ad tagging a
    kept page is still hidden.

    Source code released under MIT License

    Download file
  • Version 1.1.87

    Released Sep 25, 2026 - 103.9 KB
    Works with firefox 109.0 and later, android 120.0 and later
    Cleanup. What the extension hides, and how, is unchanged.
    • Hidden posts that leave the page are no longer kept in memory. Every
      hidden post was remembered so it could be put back, and only putting it back
      ever forgot it — so a hidden post that Facebook removed from the page stayed
      in memory, whole, until the tab was closed. Those entries are now dropped
      every few seconds, with the hide undone on the way out: Facebook reuses page
      elements, and one that came back still hidden but no longer tracked could
      never have been restored. The Diagnostics panel shows how many hidden posts
      are remembered and how many were let go.
    • The code's comments explain the code rather than its history. Dates,
      version numbers and what a panel showed on a given day belong in this file,
      and seventy comment blocks retold them. They now say why each part works the
      way it does, and keep every warning about what breaks if it changes. Two
      were simply wrong and are corrected. Comments no longer name advertisers or
      Pages. Only comment lines changed; every other line is identical.
    • A lookup written out five times is one shared helper; the diagnostics use the
      shared link parser instead of their own copy; three values nothing used are
      gone.
    • A shortcut the test harness uses to pretend it is on a different page is now
      ignored entirely in a real install.


    On a mock feed of fifty posts and about 22,000 page elements, the twice-a-second
    check takes about 1.4 ms, and the "This is an ad" hover handler 0.004–0.065 ms
    per mouse movement. Neither is worth changing. Earlier, higher figures had timed
    cold runs and the cost of the simulated mouse events, not the extension.


    49 fixtures pass. The two new behaviors were checked directly: a hidden post
    removed from the page is let go, its hide undone, and hidden again if it comes
    back; the page-address shortcut works in the harness and is ignored in a real
    build.

    Source code released under MIT License

    Download file
  • Version 1.1.86

    Released Sep 23, 2026 - 110.4 KB
    Works with firefox 109.0 and later, android 120.0 and later
    Two reports on 2026-09-23, from the same kind of ad.
    • "This is an ad" hid the picture and left the post.

    So the climb is anchored on something every post has instead: the line
    saying who posted it.
    A hide is not finished until it contains that. The
    climb keeps every guard that keeps it inside one post — it never crosses
    into the page column, a viewer, above a hidden neighbour, or into a container
    that holds another post — and if it cannot find a byline inside those
    bounds it leaves the hide exactly as it was. It can widen a hide within a
    post; it cannot widen one into the feed.

    The page name is now read from the whole post as well, which is why the list
    stayed empty: a picture's only links are /photo/ and the advertiser's own
    site, neither of which is a page.
    • Lead-form ads got through entirely. Hill's Pet Nutrition, "FORM — Enter
      for a chance to win — Sign up". That button opens a form on Facebook itself,
      so the ad never links off it; its "Ad" label is the unreadable kind; and it
      carries no dangling byline reference. Every route in missed it.

    What every ad does carry is a call to action, so that is now a third way in:
    "Sign up", "Apply now", "Get quote", "Shop now" and the rest of the words
    Facebook puts on those buttons. It only makes a card a candidate — every veto
    that protects a real post still applies afterwards. "Message", "Send
    message", "Join", "Follow" and "Interested" are deliberately not on the list:
    every marketplace listing and group post carries one of those.
    • "Hidden" now means the whole post is gone. The runner counted a post as
      hidden if a hide marker existed anywhere inside it — so a post with only
      its picture hidden passed. That is precisely the bug that reached the screen
      four times, and not one fixture could see it. There are now three outcomes:
      hidden, visible, and partial, which is never right.
    • A fixture can press "This is an ad", the way a person does — point at the
      picture, click the button — and can check which page name was recorded.
    • The Diagnostics panel reports half-hidden posts, and keeps the latest
      eight hides as samples rather than the first eight. The Renaissance half-hide
      was the seventeenth of its page, so the old panel could never have shown it.


    49 fixtures, twenty-three of them false-positive guards. Both new bug fixtures
    were confirmed to fail on 1.1.85 first — and the first draft of the
    Renaissance one did not: it gave the ad an off-Facebook link, so a second pass
    of the shape rule rescued the post and hid the lot. That is exactly what never
    happened on the real page, where nothing links off Facebook. Redrawn as a
    lead-form ad, with the click as the only thing that can hide it, it reproduces
    the report: partial on 1.1.85, hidden — and 'ads` recorded
    — on 1.1.86.

    Source code released under MIT License

    Download file
  • Version 1.1.76

    Released Sep 11, 2026 - 92.96 KB
    Works with firefox 109.0 and later, android 120.0 and later
    Ads still losing their picture and keeping everything else — Wayfair by
    screenshot, and Great Rail Journeys straight from the panel, which listed the
    same card under HIDDEN BY SHAPE and under NOT HIDDEN. 1.1.75 fixed the
    wrong half of this.
    • The climb ran out of steps. It was capped at fourteen levels, and
      Facebook nests a call-to-action block twenty-odd elements below the card, so
      a climb starting at an outbound link never reached the card and kept whatever
      fitted on the way up — the media block. Raised to thirty.

    No fixture caught this because every fixture card was four levels deep. There
    is one thirty levels deep now, and it failed before this change.
    • Nothing enforced "hide whole cards". Whatever route picks an element, if
      it is feed-post width the thing to hide is the card, so the hide now walks up
      until the next step would leave it.
    • That walk could have taken the entire feed. It stops when a parent holds
      more than one card-shaped child — but a post that is already hidden has no
      box, so a feed column with everything else hidden looks exactly like a single
      card. On a short feed it would have hidden the lot. It now asks whether the
      siblings are posts rather than whether they are visible. Found by the
      harness, before it ever ran on a page.
    • Fixtures now sit beside a neighboring post. The sixteen nesting wrappers
      were indistinguishable from a card's own — each holding one child of the same
      width — so the expand-to-card walk climbed out of the fixture and into the
      harness itself. On a real page those wrappers belong to the card; here they
      do not, and nothing said so.
    • The panel reports which rule made each hide (via label / via shape).
      Both report "sponsored", so a partial hide looked identical whichever
      produced it, and telling them apart took a screenshot and a guess.

    Source code released under MIT License

    Download file
  • Version 1.1.65

    Released Sep 11, 2026 - 78.62 KB
    Works with firefox 109.0 and later, android 120.0 and later
    • DESKTOP-AD-LABELS.md — a record of every mechanism tried against ads
      whose label cannot be read from the DOM, and how each was ruled out. Eleven of
      them: leaf text, non-leaf own text, SVG <text>, <use> sprites, live
      aria-labelledby, rescue-from-removal, a documentElement-rooted observer,
      the /ads/about/ path, CSS ::before/::after content, background-image
      and mask-image.

    Written because the answer to "have we tried X?" was becoming expensive. The
    next attempt should start from what is already eliminated.


    data-ad-rendering-role is still not an ad marker, despite being all over
    these cards and looking ideal when nothing else was left. Measured on a live
    feed: a local buy-sell group post — "Oakland County, MI Sell…" — reported

    ad-roles=profile_name,story_message,meta,title ad-preview=yes ads/about=no


    Not an ad. data-ad-preview and data-ad-comet-preview are no better; the
    same post carried those too. The long-standing warning in classifyLabel now
    carries a 2026 date and this counter-example, in the code and in the doc.


    It does not hide ads whose label is absent from the page text — the Dyson and
    Power Crunch formats. textContent on a Dyson card reads
    Dyson Verified account · Shared with Public…: the icon titles are present
    and the word "Ad" simply is not. That is not obfuscation to see through; there
    is nothing there.

    The remaining option is a shape heuristic — advertiser domain, call-to-action,
    and a byline anchor with no path — left unimplemented because it would also
    match a friend sharing a news article. The fixture corpus and its
    expect: visible guards exist to make that decision measurable if it is ever
    taken.

    Source code released under MIT License

    Download file
  • Version 1.1.56

    Released Sep 11, 2026 - 70.89 KB
    Works with firefox 109.0 and later, android 120.0 and later
    • The unhidden-card report now shows how a label could be reached, not just
      what text is present.
      Two ad cards in a row reported this shape:

    #2 680x837 cls=x1lliihq
    span:"fairlife" span:"·" a:"#fairlifepartner" span:"FAIRLIFE.COM"


    Note the span:"·" — the separator that sits after "Ad" in Facebook's
    byline — with no "Ad" text anywhere on the card. Different advertisers, same
    absence, so on these cards the label is not rendered text and the panel had
    no way to say what it actually is.

    Each card now also reports the three remaining mechanisms by which "Ad" could
    be carried: <use> sprite references and what they resolve to,
    aria-labelledby targets (falling back to the label cache when Facebook has
    already deleted the span), and plain aria-label values. Example from a
    harness card with no "Ad" text at all:

    evidence: by#lbl1->"Ad" aria:"Sponsored content"

    Whichever line carries "Ad" is what detection has to read.


    Because every fix since 1.1.51 was chosen from a console probe, and probes race
    a DOM that deleted 125 of 128 label nodes in 40 seconds. Three of them looked
    right and none landed. This reports from inside the content script, against the
    same document the scan sees, and it costs nothing until the panel is opened.

    Source code released under MIT License

    Download file
  • Version 1.1.55

    Released Sep 11, 2026 - 69.89 KB
    Works with firefox 109.0 and later, android 120.0 and later
    • The VISIBLE, NOT HIDDEN report was unreadable. Its first live run came
      back as ten identical span:"Facebook" entries per card. Those are icon
      <title> elements — leaves with text, no box, dozens per card — and taking
      the first ten in DOM order crowded out every label that mattered.

    It now reports only leaves that actually render, each text once. The same
    card in a harness goes from ten span:"Facebook" to
    span:"Verkada" span:"Ad" span:"See more".
    • Landmarks were read off the wrong element. The report used
      getAttribute on the card's outermost div, so every card looked
      landmark-less — including ones the extension anchors without trouble. It now
      uses closest() and querySelector(), and says whether the landmark is on
      the card or one of its descendants.

    This matters for the open question: the live report showed 680x781 ad cards
    with no landmarks, while posts of the same width were being hidden
    successfully. That contradiction was an artefact of where the attribute was
    read, not a fact about the page.

    Source code released under MIT License

    Download file
  • Version 1.1.54

    Released Sep 11, 2026 - 69.19 KB
    Works with firefox 109.0 and later, android 120.0 and later
    • The diagnostics panel now reports what it is missing. A VISIBLE, NOT
      HIDDEN
      section lists the post-sized cards on screen that were not hidden,
      with each card's dimensions, landmark attributes, and the short texts found
      inside it:

    VISIBLE, NOT HIDDEN:
    #1 680x783 role=- posinset=- pagelet=-
    span:"Verkada" span:"Ad" span:"See more" span:"Like"


    Three releases in a row were aimed at ads that stayed visible, each built on
    a plausible reading of a console probe, and none of them landed. The reason
    is in the numbers from an earlier run: of 128 label nodes recorded over 40
    seconds, 125 were deleted by Facebook before they could be examined
    again. Every querySelectorAll probe sampled an instant of that, and five
    consecutive probes gave five different answers.

    Reporting from inside the content script is not subject to that race. It sees
    the same document the scan sees, and it says what the label element actually
    is — whatever Facebook wraps it in this week — instead of requiring a guess.

    Computed only when the panel is opened, so it costs nothing during browsing.


    matched 10, anchored 10 on 1.1.53 means everything recognised is being
    hidden, so the ads getting through are not being recognised at all. Nothing in
    the panel could say why, because it only described what the extension did.
    This closes that gap before any further attempt at the cause.

    Source code released under MIT License

    Download file
  • Version 1.1.53

    Released Sep 11, 2026 - 67.8 KB
    Works with firefox 109.0 and later, android 120.0 and later
    • Ads whose label is drawn as SVG text were never examined. Facebook renders
      some feed-ad labels as vector text rather than a <span> — an inline <svg>
      holding <text>Ad</text>. Inspecting one on a live feed said it exactly:

    classifies as Ad: true selectable: false

    classifyLabel recognises it fine; its leaf branch reads textContent like
    any other element. But LABEL_SELECTOR listed span, a, use, [aria-label],
    [aria-labelledby]
    and not text, so the scan never handed it over. Those ads
    were never looked at, whoever the advertiser was.

    text is now in the selector. SVG text nodes are rare next to spans, and the
    selector runs once per scanned subtree rather than per element, so the cost is
    negligible.

    Verified before and after against a harness with an ad card labelled by
    <text>Ad</text> at realistic depth: 1.1.52 leaves it visible, 1.1.53 hides
    it.


    Whether those ads can then be anchored. A viewport sweep found the visible
    ad card carried no role="article", no aria-posinset and no data-pagelet,
    so findPostContainer may still have nothing to grab even now that the label is
    seen.

    The diagnostics panel answers that without further probing: if matched now
    climbs above anchored, detection is fixed and anchoring is the remaining
    problem, and the fix is a card-sized-ancestor climb of the kind
    climbToChildOf already does for the sidebar rail.

    Source code released under MIT License

    Download file
  • Version 1.1.52

    Released Sep 11, 2026 - 66.79 KB
    Works with firefox 109.0 and later, android 120.0 and later
    • Ads whose label arrives in two steps were never hidden. Facebook inserts
      the label span empty and fills it a moment later:

    html
    <span id="_r_7bt_"></span> <!-- inserted -->
    <span id="_r_7bt_">Ad</span> <!-- text arrives separately -->


    rememberLabelTarget reads "" on insertion and bails, and the text that
    follows is a text node — which the observer's addedNodes loop skipped
    outright. The label was therefore never cached and the post never
    re-examined, leaving the ad on screen with everything needed to hide it
    present in the DOM.

    Confirmed on a live desktop feed: a visible 781px sponsored post, its label
    span present reading "Ad", its referrer inside an aria-posinset and not
    in a dialog — every condition for resolution satisfied, and not hidden.

    Text nodes now complete their parent label instead of being dropped. Kept to
    O(1): only a parent carrying an id and holding no element children can be
    one of these spans, so it is a textContent read on a leaf plus a Map set,
    not a subtree walk. rememberLabelTarget resolves forward from there, so no
    extra scan is scheduled.

    Verified before and after against a harness reproducing the two-step
    insertion at realistic depth: 1.1.51 leaves the post visible, 1.1.52 hides it.
    • The diagnostics panel reports late-text labels — how many labels completed
      this way. Non-zero confirms the path is live; zero on a feed with ads means
      they are being built some other way.


    This is why the DOM probes disagreed with each other all session. Of 128 labels
    recorded over 40 seconds on a live feed, 125 were removed by Facebook before
    they could be examined again. Sampling with querySelectorAll catches an
    instant of that; only the observer sees the transitions.

    Source code released under MIT License

    Download file
  • Version 1.1.51

    Released Aug 26, 2026 - 65.65 KB
    Works with firefox 109.0 and later, android 120.0 and later
    • The extension silently did nothing on desktop. document.body was null
      when the content script ran, so this line threw:

    TypeError: MutationObserver.observe: Argument 1 is not an object
    content.js:1368


    Module evaluation stopped there. The observer never attached, the initial
    scan never ran, and main() never executed — but the message listener
    registers earlier in the file, so the popup kept answering and the extension
    looked completely healthy. Settings on, permission granted, no visible error,
    four sponsored posts sitting in the feed untouched.

    run_at: "document_idle" is supposed to guarantee a body exists. On
    facebook.com in Firefox it does not, at least sometimes. The startup now
    waits for ` to appear instead of assuming it, watchingdocument.documentElement` until it does.

    Verified before and after against a harness with document.body forced to
    null: the previous build throws, this one starts clean and completes once a
    body appears.
    • The diagnostics panel reports a BOOT: line whenever startup has not
      completed. This failure was invisible from the page and from the Browser
      Console — it only surfaced in the page console — and the panel showing
      "0 scans, 0 observer calls" after 147 seconds on a live feed is what led to
      it. Now it says so directly.


    Nothing was wrong with detection. Facebook had not changed anything: the
    labels, aria-labelledby portal spans and aria-posinset anchors were all
    present and would have resolved normally.

    Source code released under MIT License

    Download file
  • Version 1.1.50

    Released Aug 16, 2026 - 64.48 KB
    Works with firefox 109.0 and later, android 120.0 and later
    • The mobile feed stopped paging because of a single attribute write.
      1.1.49 preserved every post's height and the feed still stalled, so the
      problem was never the geometry.

    Isolated by hand on a live phone feed, with the extension installed but all
    hiding switched off:

    | What was done to 6 feed children | Feed after 15s |
    | --- | --- |
    | Nothing (extension inert) | +58 posts — paging normally |
    | data-fbsb-hidden + inline style | stalled |
    | data-fbsb-hidden only, no styling | stalled |
    | visibility: hidden on their children | +34 posts — still paging |

    Setting one data attribute, changing nothing visible, was enough to stop
    Facebook's pager for the full window. Its own observers evidently treat a
    direct feed child that has been written to as changed underneath it, and stop
    reconciling.

    So the post element is now untouchable — no style, no attribute. Both go on
    its children instead: every element child gets visibility: hidden, and the
    marker attribute rides on the first of them. The children keep their boxes,
    so the post keeps its height, and Facebook sees a feed it still owns.

    hiddenPosts is still keyed by the post, so recycled-node detection resolves
    a marker to its parent when the marker is not itself a key.

    Desktop is unchanged: it removes posts with display: none as before, and
    nothing there is virtualised or reconciled this way.


    That the feed keeps paging with the extension actually doing the hiding, over a
    long scroll — the table above was measured by hand, six posts at a time. It
    also leaves blank space where each hidden post was, which is now the only known
    remaining problem on mobile rather than one of several.

    Source code released under MIT License

    Download file
  • Version 1.1.49

    Released Aug 16, 2026 - 63.29 KB
    Works with firefox 109.0 and later, android 120.0 and later
    • The mobile feed stopped loading after about 15 seconds of scrolling, and
      it was us.
      Established by control test on stock Firefox for Android:
      extension disabled, the feed pages in new posts indefinitely; extension
      enabled, it stalls. Same account, same feed, same browser.

    Facebook virtualises that feed and decides what to page in next by measuring
    rendered content. display: none removes a post's height from that
    measurement, so hiding posts corrupts the figure the loop works from — hide
    enough and it stops paging entirely. This also explains two things that never
    quite added up: unchecking "Hide posts from Pages/Groups you don't follow",
    which hides the largest share of any feed, made the blackout go away; and
    1.1.44's pre-hiding, which hid far more posts than anything before it, made
    it dramatically worse.

    On mobile a post is now hidden with visibility: hidden instead. It becomes
    invisible while its box keeps exactly the height it had, so Facebook's
    accounting sees a feed that never changed shape.

    The cost is deliberate and visible: a hidden ad leaves blank space where it
    was, rather than vanishing.
    That is the same gap reported throughout
    testing, now accepted on purpose — blank space you can scroll past beats
    content you cannot reach. Desktop is unchanged and still removes posts
    outright; nothing there is virtualised this way.


    With placeholder mode on, mobile now shows both the placeholder bar and the
    blank space of the post behind it. Untidy, and left alone for now: the point of
    this release is to find out whether preserving height keeps the feed alive.

    Source code released under MIT License

    Download file
  • Version 1.1.48

    Released Aug 16, 2026 - 62.16 KB
    Works with firefox 109.0 and later, android 120.0 and later
    • Real timings in the diagnostics panel. Three costs, kept apart, with each
      shown as a share of wall-clock time on the page:

    over 47s on page:
    scan 312ms 0.7% (204 scans, 18422 els)
    observer 88ms 0.2% (1310 calls)
    retry 4ms 0.0% (12 ticks)


    They are separated because they fail for different reasons, and 1.1.35
    proved a healthy scan figure says nothing about the other two: it reported
    1.0ms across 274 scans while the page was unusable, because the cost was in
    the retry loop, which never calls scanRoot. The observer had the same blind
    spot until 1.1.42. Now all three are visible, and on a phone, which is where
    none of them could be read before.

    The percentage is the number worth reading. Milliseconds alone mean nothing
    without knowing over how long they accumulated.

    Scan timing was already collected in release builds — reportStats returns
    early when DEBUG is false, so nothing ever reset it — it simply had no way
    to be seen. Observer timing is now collected unconditionally too: two
    performance.now() calls per callback cost far less than what they measure,
    and a figure that only exists in a build nobody installs is not a
    measurement. Retry timing is new.

    In a DEBUG build these are a rolling 2s window rather than cumulative,
    because reportStats resets them. Worth remembering before comparing figures
    between the two builds.

    Source code released under MIT License

    Download file
  • Version 1.1.47

    Released Aug 16, 2026 - 60.88 KB
    Works with firefox 109.0 and later, android 120.0 and later
    • The mobile feed was slow to catch up, and it was the extension's fault.
      Confirmed by control test: with the extension disabled the same feed loaded
      quickly and normally.

    A label whose post Facebook hasn't rendered gets deferred to the reveal
    observer — but it was also being queued into the retry loop, which
    re-examines every entry every 50ms for a full 8 seconds. Those retries can
    never succeed: the candidate has no box and won't get one until Facebook
    reveals it, at which point the IntersectionObserver handles it anyway. On a
    virtualised feed most sponsored labels take that path, so the queue filled
    with work that was guaranteed to be wasted.

    This is the 1.1.35 regression's shape reached from a different direction — a
    flooded retry queue burning the 50ms loop — and the same lesson applies:
    queue only what can actually resolve later. Deferred labels are now left to
    the reveal observer, which is already waiting for exactly the event that
    would make them resolvable.

    unfollowed labels were already excluded on the same reasoning. This extends
    it to the case virtualisation creates.
    • The diagnostics panel reports reveals — how many scans the reveal path has
      triggered. It should track how far you have scrolled; climbing while the page
      is still means the observer is firing when it shouldn't.

    Source code released under MIT License

    Download file
  • Version 1.1.46

    Released Aug 16, 2026 - 60.05 KB
    Works with firefox 109.0 and later, android 120.0 and later
    • The breakage warning fired on every mobile page load, blaming Facebook for
      the extension working correctly.
      Observed on a real device running 1.1.45:
    [fbsb] 20 labels matched, none could be anchored to a post ... If this is
    a phone, the mobile class was probably renamed.

    The mobile class had not been renamed — the warning says so itself two lines
    earlier, reporting the gate as mobile. What actually happened is that most
    of a virtualised feed is unrendered at any moment, those candidates have no
    box, and since 1.1.45 they are deliberately deferred to the reveal observer.
    The 1.1.42 check counted every deferral as a failure to anchor, so it
    tripped its threshold on any mobile feed within a second of loading.

    A miss on a post Facebook hasn't rendered is now counted separately and
    excluded from the threshold. What remains is what the check was written for:
    labels that should have anchored against something rendered, and didn't.

    This mattered beyond the noise. The warning is not DEBUG-gated, so it
    reached anyone with a console open, and it pointed confidently at the wrong
    cause — the exact failure mode 1.1.42 was built to prevent.
    • The diagnostics panel reports deferred alongside the other counts. A large
      number there next to a healthy anchored is the reveal mechanism working,
      not failing.

    Source code released under MIT License

    Download file
  • Version 1.1.45

    Released Aug 16, 2026 - 59 KB
    Works with firefox 109.0 and later, android 120.0 and later

    Source code released under MIT License

    Download file
  • Version 1.1.44

    Released Aug 15, 2026 - 57.28 KB
    Works with firefox 109.0 and later, android 120.0 and later
    • Ads kept appearing on a phone while the badge said posts were hidden.
      Both statements were true. Facebook virtualises the mobile feed: only a
      window of posts is rendered, the rest sit at display: none with a filler
      element reserving their scroll height. Measured on a live phone feed, 42 of
      64 feed children were hidden at once, behind a filler 13,226px tall.

    A virtualised-out post reports offsetWidth 0 — it has no box. The width
    rule in findMobilePostContainer read that as "narrower than 60% of the
    feed" and returned null, so every off-screen ad was classified, rejected,
    and forgotten. Facebook then revealed it on scroll, unfiltered. The posts
    that were on screen resolved normally, which is why the badge kept
    climbing while ads stayed visible.

    The rule exists to reject nested carousel items — real boxes that happen to
    be narrow. It can say nothing about an element with no box at all, so it is
    now applied only to elements that have one. "Not currently rendered" and
    "too narrow to be a post" are different claims, and only the second is
    evidence against something being a post.

    Desktop is unaffected: nothing there is virtualised this way, so every
    candidate has a box and the rule applies exactly as before.


    Long blank gaps between posts are a separate problem with the same root.
    Facebook sizes that filler assuming the posts it virtualised still occupy
    their heights; hiding one shrinks the content without shrinking the filler.
    This release does not address that.

    It is also not yet known whether a hide applied while a post is virtualised
    out survives Facebook revealing it — if Facebook overwrites the inline style,
    the ad returns, and the observer would not notice because it watches
    childList only, not attributes. That is the next thing to measure, and the
    reason this ships as one change rather than two.

    Source code released under MIT License

    Download file
Go to Mozilla's homepage

Add-ons

  • About
  • Firefox Add-ons Blog
  • Extension Workshop
  • Developer Hub
  • Developer Policies
  • Community Blog
  • Forum
  • Report a bug
  • Review Guide

Download

  • Download Firefox
  • Windows
  • macOS
  • iOS
  • Android
  • Linux
  • All

Latest Builds

  • Nightly
  • Beta

Firefox for Business

  • Enterprise

Community

  • Connect
  • Contribute
  • Developer

Follow

  • Instagram
  • YouTube
  • TikTok
  • Bluesky
  • Podcast
  • Privacy
  • Cookies
  • Legal

Except where otherwise noted, content on this site is licensed under the Creative Commons Attribution Share-Alike License v3.0 or any later version.