SDKs

AWS CloudFront proxy

A CloudFront Function and one cache behavior on the distribution that serves your site, sending the browser SDK's calls on the issued path to Fingerly.

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

  1. 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.

  2. Step 2: Create the function

    CloudFront > Functions > Create function, runtime cloudfront-js-2.0. Paste the function the dashboard prints, function.js, whose PATH holds your path, then save and publish. The same function runs on both the viewer request and the viewer response.

  3. 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
    Origin domain:  api.fingerly.io
    Protocol:       HTTPS only
    Custom header:  x-fingerly-proxy-key = fly_px_production_…
    
  4. Step 4: Add the cache behavior

    Your path exactly, with no wildcard, and the function on both events.

    Cache behavior
    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 above
    
  5. Step 5: Point the browser SDK at the path

    fingerly.ts
    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.