Credentials
FxEmbed works best with X/Twitter account credentials to fetch post data from the Twitter API. Without them, you will have lower rate limits and not be able to fetch NSFW posts.
Credential Format
Section titled “Credential Format”Credentials are defined in a credentials.json file:
{ "twitter": { "accounts": [ { "authToken": "your_auth_token", "csrfToken": "your_ct0_csrf", "username": "account_screen_name" } ] }}You can include multiple accounts in the accounts array. FxEmbed will use them to distribute requests.
Obtaining Tokens
Section titled “Obtaining Tokens”The authToken and csrfToken values come from an authenticated X/Twitter web session. You can extract them from your browser’s cookies:
authToken: Theauth_tokencookiecsrfToken: Thect0cookie orX-Csrf-Tokenheader
Credential Management Scripts
Section titled “Credential Management Scripts”FxEmbed includes tooling to encrypt, push, and pull credentials:
Encrypt Credentials
Section titled “Encrypt Credentials”Encrypt your credentials.json using your CREDENTIAL_KEY:
npm run credentials:encryptPush to R2
Section titled “Push to R2”Upload encrypted credentials to Cloudflare R2 storage:
npm run credentials:pushEncrypt and Push
Section titled “Encrypt and Push”Combined encrypt + push in one step:
npm run credentials:encrypt-pushPull from R2
Section titled “Pull from R2”Download and decrypt credentials from R2:
npm run credentials:pullAdd CSRF Tokens
Section titled “Add CSRF Tokens”Refresh CSRF tokens for existing credentials:
npm run credentials:add-csrfStrip Credentials
Section titled “Strip Credentials”Remove sensitive data from the credentials file:
npm run credentials:stripSetting the Credential Key
Section titled “Setting the Credential Key”The encryption key must be set as a Wrangler secret so the deployed worker can decrypt credentials at runtime:
wrangler secret put CREDENTIAL_KEYBluesky
Section titled “Bluesky”FxEmbed by default will use the public Bluesky AppView API. We support specifying fallback accounts on different PDSes in the event of downtime of the public API. We will always prefer the public API unless it is down.
The proxy uses standard Bluesky app passwords
Credential Format
Section titled “Credential Format”Bluesky accounts live alongside Twitter accounts in the same credentials.json:
{ "bluesky": { "accounts": [ { "identifier": "your.handle.bsky.social", "appPassword": "xxxx-xxxx-xxxx-xxxx", "service": "https://bsky.social" } ] }}Fields:
identifier: The account’s handle (e.g.your.handle.bsky.social) or DID.appPassword: An app password generated at bsky.app/settings/app-passwords. Do not use the account’s main password.service: The base URL of the account’s PDS. For accounts hosted on Bluesky’s infrastructure, usehttps://bsky.social(the entryway will route to the correct*.host.bsky.networkPDS automatically). For self-hosted or third-party PDSes, set this to the actual PDS URL (e.g.https://pds.example.com).
Generating an App Password
Section titled “Generating an App Password”- Sign in to the account you want to use as a proxy.
- Open Settings → Privacy and security → App passwords (or visit bsky.app/settings/app-passwords directly).
- Click Add App Password, give it a descriptive name (e.g.
FxEmbed Proxy), and copy the generatedxxxx-xxxx-xxxx-xxxxvalue. - Paste it into the
appPasswordfield above.
App passwords can be revoked at any time from the same screen if a key is ever compromised.
Encryption and Deployment
Section titled “Encryption and Deployment”Bluesky credentials are encrypted, pushed, and pulled using the exact same credential management scripts and CREDENTIAL_KEY as Twitter — there’s nothing Bluesky-specific to configure on the worker side.
Instagram’s logged-out surfaces are heavily restricted: follower lists, likers, search, tagged posts and stories return nothing at all, and post and profile lookups are rate limited and gated on anything age-restricted. Adding an Instagram account proxy unlocks those surfaces and makes the existing ones far more reliable.
Without it, FxEmbed still serves Instagram posts, profiles, profile grids and comments over the logged-out web path. The proxy-only routes report HTTP 501 rather than an empty result, so you can tell “not configured” apart from “this account really has no followers”.
Credential Format
Section titled “Credential Format”Instagram accounts live alongside Twitter and Bluesky accounts in the same credentials.json:
{ "instagram": { "accounts": [ { "sessionId": "your_sessionid_cookie", "userId": "your_ds_user_id_cookie", "csrfToken": "your_csrftoken_cookie", "mid": "your_mid_cookie", "deviceId": "your_ig_did_cookie", "username": "account_handle", "platform": "web", "androidDeviceId": "android-0123456789abcdef" } ] }}Fields:
sessionId(required): Thesessionidcookie of a logged-in Instagram session.userId: Theds_user_idcookie — the account’s numeric pk.csrfToken: Thecsrftokencookie.mid/deviceId: Themidandig_didcookies. Optional, but Instagram is happier when the cookie jar looks complete.username: Used only for logging, so you can tell which session got rate limited.platform:web(default) orandroid. This picks the client fingerprint the proxy presents — see below.androidDeviceId: Optional. Sent asX-IG-Device-IDwhenplatformisandroid. Useandroid-followed by 16 hex characters (for exampleandroid-0123456789abcdef). Ignored for web sessions.
Only sessionId is strictly required; everything else improves how ordinary the session looks.
Picking a Platform
Section titled “Picking a Platform”platform must match where the sessionid came from:
web— a cookie harvested fromwww.instagram.comin a desktop browser. FxEmbed sends the matching desktop ChromeUser-Agent, web app id, and browserSec-Fetch-*/Originheaders.android— a cookie harvested from the Instagram Android app. FxEmbed sends the app’s ownUser-Agent, app id, andX-IG-Device-ID(fromandroidDeviceIdwhen set), and omits the browser-only headers.
Mixing the two is the usual cause of an unexpected checkpoint, so keep this consistent with where you got the cookie.
Obtaining a Session
Section titled “Obtaining a Session”- Sign in to the account you want to use as a proxy in a browser.
- Open DevTools → Application → Cookies →
https://www.instagram.com. - Copy the
sessionid,ds_user_id,csrftoken,midandig_didvalues into the fields above, leavingplatformasweb.
Sessions are long-lived but not permanent: logging the account out, changing its password, or an Instagram-side checkpoint invalidates the cookie. FxEmbed rotates to the next configured account on 401, 403 and 429, on an HTML login page, and on a 200 { status: 'fail' } body (checkpoint / spam block), so a stale entry degrades one account rather than the whole deployment. Use accounts you’re willing to lose, not a personal one.
Encryption and Deployment
Section titled “Encryption and Deployment”Instagram credentials are encrypted, pushed, and pulled using the exact same credential management scripts and CREDENTIAL_KEY as Twitter and Bluesky. npm run credentials:strip keeps only the cookie-jar fields, so a credentials.complete.json that also holds a login password will not leak it into the encrypted bundle.
Threads
Section titled “Threads”Threads accounts are Instagram accounts, so there is no separate credential block: the same instagram.accounts pool powers Threads. FxEmbed only swaps the client fingerprint — the Threads (Barcelona) app id and User-Agent — when it calls a Threads endpoint.
Logged-out threads.com is even more restricted than Instagram’s: search, typeahead, trending topics, likers, follow lists, and the Replies / Reposts / Media profile tabs are all behind a login. With a proxy configured those become available at /2/threads/…; without one they report 501, exactly like their Instagram counterparts. Single posts, profiles, profile timelines and conversations keep working either way — the proxy just gives fuller and more reliable results.