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.comandblog.example.comwithout 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
- In your WordPress dashboard, go to Settings > SourceTag
- Tick Enable server-side cookie setting
- 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:
- The PHP plugin runs on the
inithook (before any output) - It reads the existing
_sourcetagcookie from the request (if present) - It re-sets the same cookie via
setcookie()with a fresh expiry date, with theSecureflag (on HTTPS) andSameSite=Lax - The cookie domain is auto-detected to the root domain for subdomain support
- The browser receives this as an HTTP-header cookie, not a JavaScript cookie
- 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
- Look at your analytics to see what percentage of your traffic uses Safari
- Consider your typical sales cycle length. If most leads convert within 7 days, the Safari limitation may not matter much
- 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
| Platform | Cookie persistence in Safari |
|---|---|
| WordPress (plugin, server-side cookies enabled) | Up to 400 days |
| WordPress (plugin, server-side cookies disabled) | 7 days |
| Webflow, Squarespace, Wix, Shopify | 7 days |
| Custom site with server-side middleware | Up to 400 days |
| GTM-loaded script | 7 days |