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
403forbidden, 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-typeandx-edgekit-site-id, and decide also allowsx-edgekit-preview. Any other header,Authorizationincluded, 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.
400Missing site id.,404Unknown site.and decide’s503also 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.comis nothttps://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.
Decide answers 429 too_many_requests
Section titled “Decide answers 429 too_many_requests”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:
- 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. - The forwarder drops cookies. It must return every
Set-Cookieheader, each one separate, and forwardCookieon later requests. - 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.
/edgekit/ requests answer 502
Section titled “/edgekit/ requests answer 502”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
502with the textEdgeKit is unreachablewhen its request to your tenant host fails. CheckEDGEKIT_TENANT_HOST; - the site proxy answers
502with the textBad gatewaywhen your upstream fails. CheckEDGEKIT_UPSTREAM_URL; - your own forwarder’s
502means 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
/edgekitprefix. Forward/edgekit/a/tas/a/t; - a path rewritten to one the tenant host does not route, such as anything else under
/edgekit/.
See Route the paths.
Analytics events never arrive
Section titled “Analytics events never arrive”Find the tracker’s request in the browser’s network panel:
200with the bodyok: the collector received it.200means received, not valid: an event that fails validation is kept as a bad row rather than refused.200with the textedgekit.cloud alive: the forwarder kept the/edgekitprefix. 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. Thex-edgekit-reasonresponse header names which. The tracker does not retry a400, so the event is dropped.- Your own site’s 404 page: the analytics paths are not forwarded at all.
The site proxy serves pages unchanged
Section titled “The site proxy serves pages unchanged”The proxy leaves a response untouched when:
- a required setting (
EDGEKIT_TENANT_HOST,EDGEKIT_SITE_IDorEDGEKIT_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 not200withcontent-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 inEDGEKIT_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; a403means 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.