Skip to content

Register your origin, set your CSP, know what is sent

Register your site’s origin or every request fails

Section titled “Register your site’s origin or every request fails”

The publishable key is a signed credential minted in the dashboard. Every stream request must carry it. Test keys (st_pk_test_) work on their own for development; live keys (st_pk_live_) only work from an origin registered to your organization. Treat it like any client-side key: it is visible in page source, so protection comes from the origin registry and rate limits; rotate it from the dashboard if it leaks.

So for a live key, your site’s origin has to be registered against your organization.

The dashboard (Settings → Embedding → Origins) is the usual place to do it. On a phone the same list is under Settings → Embedding, where it is called Sites. The API works too, authenticated as your organization. The endpoint refuses any session that does not belong to the org, so nobody can register an origin against your organization id from the outside:

Terminal window
curl -X POST "https://<your-api>/api/organizations/<org-id>/embed-origins" \
-H "Content-Type: application/json" \
-H "Cookie: <your dashboard session>" \
-d '{"origin":"https://yoursite.com"}'

Until it is, every request fails CORS and your visitors read your fallback copy.

Register each origin you actually serve from, including staging and your local dev server. Wildcards are rejected: a browser never sends one, so such an entry would look like coverage while covering nothing. Plaintext http is accepted for localhost only.

If you run a Content Security Policy:

connect-src https://<your api host> # content and the copy stream
img-src https://<your CDN host> # campaign artwork, if any
media-src https://<your CDN host> # video creatives

The SDK loads no script from anywhere. The one exception is audio playback: if you call mountAudio with a Spotify track, Spotify’s own iframe API script is injected into your page, which needs:

script-src https://open.spotify.com
frame-src https://open.spotify.com

Treat that call as an explicit decision to bring in a third party.

All of this goes to your SparkleTree API and nowhere else. Disclosing it to your visitors is your obligation, so here it is plainly:

Sent Where it comes from
Time of day, day of week, timezone The device clock.
Language, coarse mobile/desktop flag navigator and a media query.
Referring origin document.referrer, reduced to its origin.
A per-tab session id Random, kept in sessionStorage.
Impressions and clicks With the campaign, the version served, where the copy came from, and whether adapted copy was on screen.
Anything you pass as context Yours.

Only the origin of the referrer is sent, never the full URL. Referrer paths and query strings routinely carry session tokens and personal data, and that value would end up in server and CDN logs.

Your page content is not in that list and the API takes no parameter for it: nothing is read out of your DOM, so the copy on your page stays yours alone. There is also no geolocation prompt, no fingerprinting, no third-party analytics, and no cross-site identifier.

Your context is merged over the collected signals and wins, so overriding one with undefined removes it:

<SparkletreeProvider publishableKey={KEY} context={{ referrer: undefined }}>

storage controls where the visitor’s “show me the standard version” preference is kept. Pass your own store if a consent manager gates localStorage, or if your test environment does not provide one.

That preference is its whole scope. The per-tab session id and the impression and click events are sent regardless; to stop those, do not render the components.

The fragment read request carries no credentials and no prose from your page, only three identifiers: your organization id, the context hash, and the schema hash. That is why it can be served from a shared cache. Your fallback strings never appear in a URL. The write request, which spends credits, is the one that takes a signed token.