Skip to content
Maps Embed

Authentication

API keys and domain whitelisting.

API key

You get one key per org. It starts with emb_ and is 68 characters long. Keys can be viewed and rotated from the admin dashboard. After a rotation the old key stops working within 5 minutes, because key lookups are cached for that long. Plan the swap with that window in mind, and treat a leaked key as live until it has passed.

Pass it as a query param:

/sol/scanner/{ADDRESS}/map?embed=1&key=emb_a1b2c3d4e5f6...
/rh/scanner/{ADDRESS}/map?embed=1&key=emb_a1b2c3d4e5f6...

Embed keys are publishable: they sit in your page's HTML, so treat them like a public identifier rather than a secret. Your domain list controls where the map can be framed and filters API calls on a best-effort basis. Your usage limits are what bound spend on a key.

Domain whitelisting

Both chains use the same key and domain settings.

No domains configured (public mode). If your org has no allowed domains, the key works on any site: the iframe can be framed anywhere and API calls are accepted from any origin. This is the default for a new org until you ask us to add domains.

Domains configured. Once at least one domain is set:

  • The iframe response sets a Content-Security-Policy: frame-ancestors rule for your domains, and the browser blocks embedding on other sites.
  • API calls from inside the iframe originate from Scanner itself, so the backend trusts Scanner's frontend origin while separately validating the embed key and quota.
  • Direct API calls from other origins are checked against the allowed-domain list and receive 403 EMBED_DOMAIN_REJECTED if rejected.
  • Requests that carry the key but send neither an Origin nor a Referer header (for example curl or a server-side fetch) are rejected with 403 EMBED_DOMAIN_REJECTED. Browsers always send Origin on the iframe's own API calls, so real embeds are unaffected.

Server-to-server calls

Embed keys are for browsers. If you need Scanner data from your backend, use an sk_live_ API key instead; see API keys. Header checks are a filter, not authentication: a script can send any Origin it likes, which is why quotas and rate limits apply to every key.

Matching rules:

You registerWorks onDoesn't work on
app.example.comapp.example.comexample.com, other.com
example.comexample.com, sub.example.comother.com
localhosthttp://localhost:3000, http://localhost:5173 (any port)Remote origins
localhost:5173http://localhost:5173 onlyOther ports

If you add example.com, all subdomains work too. To add or change domains, contact us.

Local development

For dev environments, register either localhost (matches any port) or the specific localhost:PORT you run your integrator on. Both schemes http:// and https:// are accepted by the iframe's frame-ancestors CSP.

Validate a key

Check if a key is valid without triggering a scan:

GET https://api.scanner.net/embeds/validate?key={API_KEY}

No auth needed. Returns:

{ "valid": true, "domains": ["app.example.com", "staging.example.com"] }

Or if invalid:

{ "valid": false, "domains": [] }

Use this before mounting the iframe to fail fast when a key is rotated, disabled, or typo'd: the iframe itself cannot report invalid-key state to the host page (cross-origin), so a pre-flight check is the cleanest way to surface it.

Errors

StatusCodeMeaning
403EMBED_KEY_INVALIDBad key or key not found
403EMBED_ORG_DISABLEDOrg disabled by admin
403EMBED_DOMAIN_REJECTEDThe request's Origin (or Referer) is not on your domain list, or your org has domains set and the request sent neither header. Check the page's domain against your list; for server-to-server calls, use an sk_live_ API key

View this page as Markdown