Troubleshooting

Safari Cookie Limitations

Safari’s Intelligent Tracking Prevention (ITP) limits cookies set by JavaScript to a maximum of 7 days. This applies to all browsers using the WebKit engine, including Safari on macOS, Safari on iOS, and any browser on iOS (Chrome, Firefox, and Edge on iOS all use WebKit under the hood).

What this means for attribution

SourceTag stores attribution data in a cookie. On most browsers, this cookie persists for 400 days (or whatever lifetime you’ve configured). On Safari, the cookie expires after 7 days regardless of what lifetime is set.

In practice:

  • A visitor arrives from a Google Ads click on Monday. SourceTag captures their attribution as Paid Search.
  • They don’t come back until the following Wednesday (9 days later).
  • On Safari, the cookie has expired. SourceTag treats them as a new visitor with no history.
  • If they arrive directly (no UTMs, no referrer), they’re categorised as Direct. The original Paid Search attribution is lost.

This only matters if your sales cycle is longer than 7 days and a meaningful portion of your traffic uses Safari. In New Zealand and Australia, Safari accounts for roughly 30-40% of web traffic. In the US, it’s around 25-30%.

Server-side cookie mechanism

SourceTag supports server-side cookie setting to bypass ITP. When enabled, the cookie is set via an HTTP Set-Cookie header rather than JavaScript. Safari treats server-set cookies differently and allows them to persist for up to 400 days.

The server-side cookie is configured with:

  • Secure flag set on HTTPS sites (the cookie is only sent over encrypted connections)
  • SameSite=Lax (protects against CSRF while allowing normal navigation)
  • Cookie domain auto-detection (automatically set to the root domain, so it works across subdomains like www.example.com and blog.example.com without manual configuration)

The data-server-cookie attribute

For non-WordPress sites that can handle server endpoints, SourceTag supports a data-server-cookie attribute on the script tag. This tells the script to send a request to a server-side endpoint that sets the cookie via HTTP headers.

<script src="https://cdn.sourcetag.io/scripts/YOUR_SITE_ID/st.js"
  data-server-cookie="/api/sourcetag-cookie" async></script>

The endpoint receives the cookie data and sets it via a Set-Cookie header, giving it the same 400-day persistence in Safari.

The WordPress plugin fix

The SourceTag WordPress plugin has a server-side cookie option that uses this mechanism automatically.

When enabled, the plugin uses PHP’s setcookie() function to set the _sourcetag cookie via an HTTP Set-Cookie header on every page load. Safari treats cookies set by the server differently from cookies set by JavaScript. Server-set cookies are allowed up to 400 days of persistence.

How to enable it

  1. In your WordPress dashboard, go to Settings > SourceTag
  2. Tick Enable server-side cookie setting
  3. Click Save Changes

[IMAGE: Screenshot of the WordPress SourceTag plugin settings page with the server-side cookie toggle]

How it works

On every page load:

  1. The PHP plugin runs on the init hook (before any output)
  2. It reads the existing _sourcetag cookie from the request (if present)
  3. It re-sets the same cookie via setcookie() with a fresh expiry date, with the Secure flag (on HTTPS) and SameSite=Lax
  4. The cookie domain is auto-detected to the root domain for subdomain support
  5. The browser receives this as an HTTP-header cookie, not a JavaScript cookie
  6. Safari allows this cookie to persist for up to 400 days

The JavaScript script still runs and updates the cookie value with new attribution data. The PHP plugin simply refreshes the expiry on every page load to keep it alive.

Requirements

  • WordPress site
  • SourceTag WordPress plugin installed and activated
  • Pro plan or higher
  • PHP must run on every page view. If you’re using a full-page caching plugin (WP Rocket, W3 Total Cache, LiteSpeed Cache), the PHP hook may not execute on cached pages. See the note on caching below.

Caching considerations

Full-page caching serves a static HTML file without running PHP. When this happens, the setcookie() call in the plugin never runs, and the Safari cookie won’t get refreshed.

Options:

  • Exclude pages with forms from the full-page cache. This ensures PHP runs on the pages that matter.
  • Configure the cache to vary by cookie. Some caching plugins can check for the presence of a specific cookie and skip the cache if it exists.
  • Use a caching plugin that supports PHP hooks. Some caching plugins run certain early hooks even on cached pages.

Non-WordPress sites

For sites running on a platform that supports server-side code (Node.js, PHP, Python, Ruby), you can use the data-server-cookie attribute described above. Create an endpoint that reads the _sourcetag cookie from the incoming request and sets it again in the response with a fresh expiry via an HTTP Set-Cookie header.

For purely static platforms (Webflow, Squarespace, Wix, Shopify) where you can’t add server-side endpoints, the JavaScript cookie is subject to Safari’s 7-day limit.

We’re exploring a first-party proxy approach that would work across all platforms. No timeline on this yet.

How to check if you’re affected

  1. Look at your analytics to see what percentage of your traffic uses Safari
  2. Consider your typical sales cycle length. If most leads convert within 7 days, the Safari limitation may not matter much
  3. Check your CRM data for leads with missing first-contact attribution. If there’s a pattern of Safari users having “Direct” as their first contact channel despite arriving from campaigns, ITP is likely the cause

Summary

PlatformCookie persistence in Safari
WordPress (plugin, server-side cookies enabled)Up to 400 days
WordPress (plugin, server-side cookies disabled)7 days
Webflow, Squarespace, Wix, Shopify7 days
Custom site with server-side middlewareUp to 400 days
GTM-loaded script7 days