Facebook Post Shim
When ETP blocks the Facebook SDK, embedded posts disappear completely. This shim renders click-to-load placeholders so users know the content exists.
Bug 1698840 | D275716 | Reviewer: manuel
The Problem
Facebookโs XFBML system uses <div class="fb-post"> elements that get rendered by the Facebook SDK JavaScript. When Firefoxโs Enhanced Tracking Protection (Strict mode) blocks the SDK, these elements never get processed. The result is invisible: the <div> is there in the DOM but renders as nothing. Users donโt even know a post was supposed to be there.
Firefox already had a SmartBlock shim for the Facebook SDK that handled login buttons and video embeds. But it didnโt know about fb-post elements.
The Implementation
I extended the existing facebook-sdk.js shim with a new makePostPlaceholder() function:
async function makePostPlaceholder(target) {
if (target.hasAttribute("fb-xfbml-state")) {
return;
}
target.setAttribute("fb-xfbml-state", "");
let width = parseInt(target.getAttribute("data-width")) || 500;
width = `${width}px`;
const placeholder = document.createElement("div");
placeholdersToRemoveOnUnshim.add(placeholder);
placeholder.style = `
width: ${width};
min-height: 200px;
padding: 24px;
background: light-dark(#f0f2f5, #242526);
border: 1px solid light-dark(#dddfe2, #3e4042);
border-radius: 8px;
color: light-dark(#1c1e21, #e4e6eb);
text-align: center;
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 12px;
`;
// Facebook logo icon + "Click to allow blocked Facebook content"
...
target.appendChild(placeholder);
}The placeholder respects the data-width attribute that site authors use to control embed size, and uses light-dark() CSS function to work in both light and dark mode.
Detection
The shim detects fb-post elements in two places:
- On page load:
FB.XFBML.parse()is called by sites after the SDK loads. The shim intercepts this call and processesfb-postelements. - Dynamically: A
MutationObserverwatches forfb-postelements added after initial page load (common in single-page apps).
When a user clicks the placeholder, the shim triggers the full SDK load, removing all placeholders and letting Facebookโs real rendering take over.
Testing
Added a test HTML file (test_facebook_post_embed.html) that verifies three scenarios:
- Static
fb-postelements present at page load - Dynamically added
fb-postelements - Custom
data-widthattributes being respected
Total: 2 files changed, +143 lines.
What I Learned
- Shims are a middle ground between blocking and allowing. Rather than fully blocking or fully allowing the Facebook SDK, the shim gives users informed consent: they can see that content exists and choose to load it. This is a privacy-respecting UX pattern.
- The
light-dark()CSS function is great. It lets you write a single value that adapts to the userโs color scheme without media queries. I hadnโt used it before but itโs perfect for injected content that needs to match the browserโs theme.