Skip to content

Security and CSP

The Flume iframe loads only inside pages on origins you agreed with Flume. Your partner key and user access tokens stay on your server. This page lists what Flume enforces, what your page must allow, and what to trust.

Flume holds three lists per partner. Flume sets them. You cannot read or change them yourself today.

ListFormatUsed for
Allowed originsExact origins: scheme, host and port, no path, no trailing slashWhich pages may frame the iframe. Checked against host_origin on every session start
Image hostsExact host namesWhich hosts Flume may fetch item.image_urls from
Redirect hostsExact host namesWhich hosts a deep link's redirect_uri may name
  • To add or change an entry, ask Flume.
  • A change to allowed origins can take up to 60 seconds to apply.
  • Sandbox and live each have their own lists.
  • A local origin such as http://localhost:3000 can be an allowed origin in the sandbox. See Develop on localhost.

Flume sends these headers with the iframe document.

HeaderValueEffect
Content-Security-Policyframe-ancestors followed by your allowed originsOnly your pages can frame it
Content-Security-Policyframe-ancestors 'none' for an unknown or inactive partnerThe frame stays blank
Cache-Controlno-storeThe document is never cached
Referrer-Policyno-referrerThe iframe URL is not leaked in a referrer
X-Content-Type-OptionsnosniffThe browser does not guess content types

Also:

  • The iframe runs only when framed. Opened in its own tab, it does not start.
  • The iframe's own policy allows scripts only from Flume's own hosts and its analytics host, and blocks nested frames.
  • The launch code travels in the URL fragment, which browsers do not send to a server.
  • The iframe removes the launch code from its URL as soon as it has read it.

If your page sends a Content-Security-Policy, add these.

DirectiveAddWhy
frame-srcThe iframe originTo frame the iframe
img-srcThe origin of the image linksOnly if your page shows Flume image links directly
connect-srcThe origin of the image linksOnly if your page fetches image bytes with fetch
  • The iframe origin is new URL(iframe_url).origin. Read it once per environment from a real response, then add it to your policy.
  • The origin of the image links is the origin of a link in a real payload, for example new URL(payload.product.gallery[0].urls[key]).origin. Read it once per environment.
  • Do not assume either origin equals the host your server calls. In the sandbox they can differ.
  • Ask Flume before go-live whether those origins are about to change.
  • If your page sends Cross-Origin-Embedder-Policy: require-corp, the browser blocks the iframe.

Twelve rules. An integration that breaks one is not finished.

#RuleDetail
1The partner key and every user access token stay on your server. Never in a browser, a client bundle, a log or a commitKeys and tokens
2Only your server calls Flume. A server call cannot be made from a browserServer calls
3Every server call sends X-Flume-Partner-Key. POST /start-iframe-session also sends X-Flume-User-Token whenever you hold a token for the userServer calls
4iframe_url, its launch code and the connect code are single use and short lived. Use each at once. Never store, log, rebuild or edit themTimeouts and expiry
5Read the iframe's origin from iframe_url. Never hardcode itSet up your page
6Drop a message unless its origin, source, version and session_uuid are right. Ignore types you do not knowMessages
7Reply to the iframe with its origin as the target origin, never "*"Messages
8Answer every flume:save_item within 60 seconds, with flume:item_saved or flume:item_save_failed, carrying its save_uuid. A repeated save_uuid writes nothing twiceMessages
9Exchange every connect code at once. Store the new token over the old oneUsers and verification
10Run a ready timer of 15 seconds. When it fires, remove the iframe and show an error with a retryTimeouts and expiry
11On 401 USER_TOKEN_INVALID, delete the stored token and start again without it. On 429, wait for Retry-After. Branch on error.code, never on error.messageErrors
12The save payload came through the browser. Render its text as text, and do not treat a saved price as a commitmentBelow

The host snippet keeps rules 5 to 8 and 10 for you when you copy it unchanged.

Your message listener receives every message sent to your window. Make the four checks on each one, and reply with the iframe's origin as the target, never "*". The host snippet does both.

The save payload reaches your backend through the user's browser. Treat it like any other browser input.

  • The four message checks prove the message came from the Flume iframe. They do not stop a user from changing a request to your own backend.
  • Flume offers no server call to read the payload again. So do not treat a saved price as an order or a commitment. It is what the user saw, valid until pricing.valid_until.
  • Check on your server that the item being written belongs to the signed-in user.
  • Render every string as text. See Text rules.

POST /users/exchange-connect-code returns external_ref: your own id for the user who verified.

  1. Compare it with the user who is signed in to your product.
  2. Store the token only when they match.
  3. If they differ, discard the token.
Where each secret lives and travelsLong-lived secrets stay on servers. Only single-use, short-lived codes pass through the browser. The same content is listed as text under the diagram.Browser: single-use codes onlyServers: secrets stay hereYour pagechecks origin, source,version, session_uuidYour backendpartner keyuser access tokensFlume iframeposts only to host_originits own short credentialFlume serversallowed originsper partneriframe_url (launch code)connect_codepartner key,user access tokeniframe_url,access_tokensave repliesconnect_code,save payloadlaunch code, onceYoursFlume'sServer call (HTTPS)postMessageThe iframe's own call

Where each secret lives and travels. Long-lived secrets stay on servers. Only single-use, short-lived codes pass through the browser.

Read this diagram as text
  1. Your backend holds the partner key and each user access token. It sends them only to Flume, over HTTPS.
  2. Flume returns iframe_url, which carries a launch code. The launch code works once, within 120 seconds.
  3. Your backend hands iframe_url to your page. Your page sets it as the iframe src and stores it nowhere.
  4. The iframe spends the launch code with Flume and then uses its own short-lived credential.
  5. When a user verifies, the iframe posts a connect code to your page. It works once, within 120 seconds.
  6. Your page passes the connect code to your backend, which exchanges it for the user access token.
  7. Your page accepts a message only when its origin, source, version and session_uuid are right. The iframe posts only to the host_origin you sent.
CredentialWhere it livesReaches the browser
Partner keyYour serverNever
User access tokenYour serverNever
Connect codePasses through your page onceYes. Single use, 120 seconds
Launch code, in iframe_urlPasses through your page onceYes. Single use, 120 seconds
The iframe's own credentialInside the iframeYes, inside the iframe only. Your page cannot read it

Flume stores every key, token and code as a hash only.

When you send item.image_urls, Flume's server fetches the first photo.

  • https only.
  • The host must be on your image host list.
  • Redirects are not followed.
  • 10 second timeout, 25 MB limit.
  • The links must stay reachable for the session's life.

An entry that breaks a rule is a 422 VALIDATION_FAILED naming item.image_urls.<index>.

  • Every string in the save payload. Flume removes control characters and angle brackets only. Quotes and & remain.
  • Render strings as text. Escape them on output. Never build HTML or an HTML attribute from them by joining strings.
  • Every message, until it passes the four checks above.

Contact Flume. Send the key prefix and X-Request-Id values. Never send a key or a token.