Skip to content

Troubleshooting

Every client API and decide error answers { "error": { "code", "message" } }. The codes below are from the error code reference. Analytics refusals carry no body.

The browser reports a CORS error on an EdgeKit request

Section titled “The browser reports a CORS error on an EdgeKit request”

A CORS error means the request was cross-origin: your page called the tenant host, not /edgekit/ on its own domain. Through the mount there is no CORS at all. Cross-origin, these cause it:

  • The origin was refused. The request answered 403 forbidden, and a refusal carries no CORS headers, so the browser hides the body. Add the page’s origin to the site’s Allowed origins and deploy. See the next question.
  • A request header is not allowed. The preflight allows content-type and x-edgekit-site-id, and decide also allows x-edgekit-preview. Any other header, Authorization included, fails the preflight.
  • The route does not serve the method. The preflight answers it without permission headers.
  • The request was refused before the origin check. 400 Missing site id., 404 Unknown site. and decide’s 503 also carry no CORS headers. Send the same request with cURL to read the answer; see Verify the mount.

A request answers 403 forbidden: “This origin is not allowed for the selected site.”

Section titled “A request answers 403 forbidden: “This origin is not allowed for the selected site.””

The request’s Origin is not in the site’s Allowed origins. Check, on Delivery › Delivery › Sites:

  • the exact origin, scheme and host and port: https://www.example.com is not https://example.com;
  • that the list is not empty. An empty list refuses every browser request that carries an Origin;
  • that you deployed after the last change. Requests read the deployed site.

Without an Origin, the same 403 means the browser’s Sec-Fetch-Site header said the request was not same-origin, or the request was a page navigation. A forwarder that strips Origin causes this on any request that is not same-origin.

A request answers 400 bad_request: “Missing site id.”

Section titled “A request answers 400 bad_request: “Missing site id.””

The request carried no x-edgekit-site-id header. The browser client sends it on every request, so a forwarder in between is dropping it. Forward the header unchanged. Analytics requests do not need it.

A request answers 404 not_found: “Unknown site.”

Section titled “A request answers 404 not_found: “Unknown site.””

The site id names no active site in your organization’s deployed configuration. Either the id is wrong, the site is disabled, or the site was added and not yet deployed. A new site answers only after a deploy on Delivery › Deployments › Versions.

Decide answers 503 service_unavailable: “This tenant has no deployed configuration.”

Section titled “Decide answers 503 service_unavailable: “This tenant has no deployed configuration.””

Decide found no deployed configuration for your organization. EdgeKit makes your organization’s first deploy when it opens your account, so an organization that is set up does not start in this state. Stage and deploy the draft on Delivery › Deployments › Versions. Without Retry-After, a retry does not help until a deployment reaches decide.

Decide from the browser answers 401 unauthorized: “Missing API key.”

Section titled “Decide from the browser answers 401 unauthorized: “Missing API key.””

The request reached /v1/decide, which takes an API key, instead of /edgekit/v1/decide. Your forwarder removed /edgekit from the path. Forward /edgekit/v1/* with the path unchanged.

The browser decide path allows 200 requests per 10 seconds per client per site, and answers 429 with Retry-After: 10 past it. EdgeKit identifies the client by the address that connects to your tenant host. Behind a forwarder, that can be the forwarder’s own address, so many users share one budget. The site proxy avoids this by signing each user’s IP address with EDGEKIT_CLIENT_IP_KEY; see Rate limits behind the proxy.

Sign-in succeeds but the next request is anonymous

Section titled “Sign-in succeeds but the next request is anonymous”

The sign-in cookie did not come back. Check, in order:

  1. The page calls the tenant host directly. The browser sends the sign-in cookie there only when the user signed in through the tenant host and it shares your site’s domain, or when your organization’s cookie domain covers both hosts. Otherwise use the /edgekit/ path on your own domain.
  2. The forwarder drops cookies. It must return every Set-Cookie header, each one separate, and forward Cookie on later requests.
  3. The page is served over plain HTTP. EdgeKit’s sign-in cookies are Secure, and browsers do not store them there.

Requests that need a signed-in user answer 401 unauthorized without the cookie. Decide answers 200, as for an anonymous device.

502 is not an EdgeKit error code: EdgeKit’s own routes never answer it. Your forwarder, or the site proxy, answers it when it cannot get a response:

  • the site proxy answers 502 with the text EdgeKit is unreachable when its request to your tenant host fails. Check EDGEKIT_TENANT_HOST;
  • the site proxy answers 502 with the text Bad gateway when your upstream fails. Check EDGEKIT_UPSTREAM_URL;
  • your own forwarder’s 502 means it could not reach the tenant host. Check the target host name, and that the forwarder connects over HTTPS with the tenant host as the server name.

An /edgekit/ request answers 200 with the text “edgekit.cloud alive”

Section titled “An /edgekit/ request answers 200 with the text “edgekit.cloud alive””

The request reached your tenant host on a path it does not serve, and the host answered with its plain-text liveness response. The browser client reads it on decide as decide being unavailable. Two common causes:

  • an analytics path forwarded with its /edgekit prefix. Forward /edgekit/a/t as /a/t;
  • a path rewritten to one the tenant host does not route, such as anything else under /edgekit/.

See Route the paths.

Find the tracker’s request in the browser’s network panel:

  • 200 with the body ok: the collector received it. 200 means received, not valid: an event that fails validation is kept as a bad row rather than refused.
  • 200 with the text edgekit.cloud alive: the forwarder kept the /edgekit prefix. The tracker counts the event as delivered, so it is lost.
  • 400: the collector refused the request as malformed: a path it does not serve, a body it cannot parse or that is too large, or a method it does not accept. The x-edgekit-reason response header names which. The tracker does not retry a 400, so the event is dropped.
  • Your own site’s 404 page: the analytics paths are not forwarded at all.

The proxy leaves a response untouched when:

  • a required setting (EDGEKIT_TENANT_HOST, EDGEKIT_SITE_ID or EDGEKIT_UPSTREAM_URL) is missing or invalid. Your copy logs a warning for it when it starts;
  • the request is not a GET, or the response is not 200 with content-type: text/html;
  • the page is larger than 2 MB.

It serves the whole page, adding only its two scripts to <head>, when:

  • the path matches EDGEKIT_IGNORE_PATHS, or the request is from a verified bot in EDGEKIT_BYPASS_BOT_CATEGORIES;
  • decide failed, answered an error status or missed its 2-second deadline. The decision script then says unavailable. Your copy logs the status decide answered; a 403 means your site’s origin is not in Allowed origins.

On a page the proxy processed, the <script id="edgekit-decision"> in the page source names the mode it chose.

The site proxy covers every page with a panel

Section titled “The site proxy covers every page with a panel”

A page whose outcome does not allow it gets the panel, and so does every page when the deployment has no paywall feature for the site: decide then lists paywall as unknown, and the proxy gates the page. Check that the feature is deployed and runs on the site. To keep pages such as your home page, account and checkout screens out of decisions, list them in EDGEKIT_IGNORE_PATHS.