flowsk.com
Getting started

Proxy setup — the ITP-proof install

Your server owns the visitor id and forwards events from your own origin. About an hour of work, and it is the difference between a 7-day attribution window and a real one.

Aug 4, 2026· 3 min read ·Docs
Quick answer

your server sets the cookie → your origin receives events → you forward server-to-server

Three changes: mint the id in a Set-Cookie response header, accept events on your own domain, forward them to the Flowsk API from your backend. After this, Safari's 7-day cap does not apply and no blocklist contains any domain involved.

This is not CNAME cloaking. It is your own backend running your own code — nothing is disguised as first-party, because it is first-party.

The snippet gets you tracking in five minutes and gives you exactly the identity durability every other JavaScript tracker has: seven days in Safari.

This page removes that limit. Budget an hour.

Why it works

Safari’s ITP caps the expiry of cookies written through document.cookie. It does not cap cookies written by a server in a Set-Cookie response header — which is why your login session survives for months while your analytics id does not.

So: stop writing the id from JavaScript.

Step 1 — your server mints the id

On every request, read the cookie; if it is missing or malformed, mint a UUID and set it.

Rails

# app/controllers/concerns/flowsk_identity.rb
module FlowskIdentity
  extend ActiveSupport::Concern
  COOKIE = :_fsk_id
  UUID_RE = /\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/i

  included { before_action :flowsk_visitor_id }

  private

  def flowsk_visitor_id
    existing = cookies[COOKIE]
    return existing if existing.present? && existing.match?(UUID_RE)

    SecureRandom.uuid.tap do |id|
      cookies[COOKIE] = { value: id, expires: 2.years, httponly: false, same_site: :lax }
    end
  end
end

Next.js

// middleware.ts — runs per request, before rendering, even for static pages
import { NextResponse } from "next/server"
import type { NextRequest } from "next/server"

export function middleware(request: NextRequest) {
  const response = NextResponse.next()
  if (!request.cookies.get("_fsk_id")) {
    response.cookies.set("_fsk_id", crypto.randomUUID(), {
      maxAge: 60 * 60 * 24 * 730, sameSite: "lax", path: "/", httpOnly: false
    })
  }
  return response
}

PHP / WordPress

add_action('init', function () {
  if (empty($_COOKIE['_fsk_id'])) {
    setcookie('_fsk_id', wp_generate_uuid4(), [
      'expires' => time() + 63072000, 'path' => '/',
      'samesite' => 'Lax', 'secure' => true, 'httponly' => false,
    ]);
  }
});

httponly: false lets the snippet read the same id, so the client and server sides share one identity. Set it to true only if your backend emits every event itself.

Step 2 — accept events on your own origin

A small endpoint on your domain. Nothing on the page talks to a third-party host, so no blocklist and no third-party request filter is involved.

// app/api/events/route.ts
export async function POST(request: Request) {
  const body = await request.json()
  const anonymousId = request.headers.get("cookie")?.match(/_fsk_id=([^;]+)/)?.[1]

  await fetch("https://flowsk.com/api/events", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      write_key: process.env.FLOWSK_WRITE_KEY,
      anonymous_id: anonymousId,
      events: body.events
    })
  })

  return new Response(null, { status: 204 })
}

Two details worth getting right:

  • Read the id from the cookie server-side, not from the request body. The browser cannot lie about it, and it stays correct even if the snippet failed to load.
  • Return immediately. Do not make your visitor wait on our API. Enqueue if your framework makes that easy.

Step 3 — point the snippet at your endpoint

<script async src="https://flowsk.com/flowsk.js"
        data-write-key="pk_live_…"
        data-endpoint="/api/events"></script>

Step 4 — confirm conversions server-side

The purchase must not depend on the browser at all. From your payment webhook, post directly to the Flowsk API with source: "server" and the order id as the dedup_key — see the events API and de-duplication.

Verifying it

  1. Load your site in a private window.
  2. Check the response headers for Set-Cookie: _fsk_id=… with a long Max-Age.
  3. Run the cookie inspector against your URL — the cookie should appear with Survives ITP: yes.
  4. Open a journey in the app and confirm events are landing with your visitor id.

What you have after this

  • A visitor id that lives as long as you set it, in every browser.
  • No third-party request on the page for anyone to block.
  • Conversions confirmed by the system that took the money.
  • An attribution window that means what it says.

flowsk.com runs exactly this configuration on itself — how we dogfood it.

Frequently asked questions

How is this different from CNAME cloaking?

CNAME cloaking points a subdomain at a third-party host so a third-party request appears first-party. Browsers detect it and it degrades every year. Here, your backend genuinely receives the request, and forwards it server-to-server. There is nothing to detect because nothing is disguised.

Do I still need the snippet?

Yes, for behaviour — pageviews, clicks, submits. What changes is that it reads an id your server already set instead of minting its own, and posts to your origin instead of ours.

What if my site is fully static or on a CDN?

Edge middleware works — Next.js middleware, Cloudflare Workers, Netlify Edge Functions. Any layer that runs per request on your domain can set the cookie.

Does page caching break it?

It can. A full-page cache may serve a response whose Set-Cookie was generated for someone else, or strip it entirely. Exclude the cookie-setting path from cache, or set the id from a tiny uncached endpoint.

Should the cookie be HttpOnly?

If your backend owns identity end to end, yes. If the snippet also needs to read the id, keep it readable — durability comes from who wrote it, not from the flag.

Confirm it worked

Run the cookie inspector against your own site. A durable server-set first-party cookie should now appear in the table.

Inspect my cookies

Stop guessing which ad made the sale.

Flowsk Signals stitches the anonymous click to the email to the purchase — first-party, server-side, de-duplicated. One snippet, $29/mo, and every conversion comes with a receipt you can inspect.

Keep reading