A CloudFront Function and a cache behavior for the distribution that already serves your site. The behavior answers one path the dashboard issued, on your own domain, and sends only the browser SDK's submissions to Fingerly as its origin. It is not an open proxy: the origin is api.fingerly.io, the function rewrites every request to one URL on it, and every other method is refused. Version 1.0.0.
Set up
Step 1: Create the proxy
In the dashboard, open Integration > Proxy keys and choose New proxy. Pick the environment of the public key it will forward, and AWS CloudFront under How it runs. Copy the proxy key it shows once, and note the path it issued, such as
/k7x2qm4a.The dashboard then prints the steps below, filled in with your proxy's own path and key. They stay under Show setup in the proxy's menu, without the key, which is never shown again.
Step 2: Create the function
CloudFront > Functions > Create function, runtime
cloudfront-js-2.0. Paste the function the dashboard prints,function.js, whosePATHholds your path, then save and publish. The same function runs on both the viewer request and the viewer response.Step 3: Add the origin
In the distribution that serves your site. The custom header carries the proxy key, and CloudFront always overwrites a viewer-sent header of the same name, so a visitor cannot supply their own.
Origin domain: api.fingerly.io Protocol: HTTPS only Custom header: x-fingerly-proxy-key = fly_px_production_…Step 4: Add the cache behavior
Your path exactly, with no wildcard, and the function on both events.
Path pattern: /k7x2qm4a Origin: api.fingerly.io Viewer protocol policy: HTTPS only Allowed HTTP methods: GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE Cache policy: CachingDisabled Origin request policy: AllViewerExceptHostHeader Viewer request: CloudFront Functions, the function above Viewer response: CloudFront Functions, the function aboveStep 5: Point the browser SDK at the path
import { load } from '@fingerly/web-js' const fingerly = await load({ apiKey: 'fly_pk_production_…', endpoints: '/k7x2qm4a', })The SDK posts both of its calls to the path exactly as given. Once pages use it, the proxy's row in Proxy keys shows it last seen, running
aws-cloudfront/1.0.0, with its requests over the last 30 days.
With CloudFormation
The dashboard also prints cloudformation.yaml: the same function, plus the parameter, origin and cache behavior to merge into your distribution's template. Pass the key as the FingerlyProxyKey parameter. It is NoEcho, so the key stays out of the template and out of version control.
How the visitor's address is trusted
The function sends event.viewer.ip, the address CloudFront accepted the connection from, as x-fingerly-client-ip. It is not read from any header, so the visitor cannot change it.
The proxy key lives in the origin configuration, not the function, so unlike the other templates there is no key check in the code. Without the origin header, the API refuses every call with 401 and proxy_key_missing, because the function still sends the visitor's details. Add the header before routing traffic.
What it sends and relays
Upstream, to https://api.fingerly.io/api/v1/ingest only: the viewer's request with every cookie, Authorization and any visitor-sent x-fingerly-* header removed, plus the x-fingerly-* headers the function sets (the visitor's address, the page origin, the user agent and x-fingerly-proxy-version: aws-cloudfront/1.0.0) and the proxy key from the origin's custom header. Other methods answer 405 with Allow: POST.
CloudFront Functions cannot read request bodies, so the body passes through unchanged and CloudFront's own request limits apply rather than a 1 MiB cap. The API enforces its own limit.
Back to the page: the viewer response keeps only content-type, x-request-id, ratelimit-limit, ratelimit-remaining and retry-after (and the framing headers CloudFront manages), drops every cookie and sets cache-control: no-store. CloudFront adds its own Via and X-Cache style headers after the function runs; none of them names Fingerly.