Skip to content

Commit 9418356

Browse files
committed
feat(post): Add Safari 7-day consent post
1 parent 8122f72 commit 9418356

File tree

3 files changed

+107
-4
lines changed

3 files changed

+107
-4
lines changed

.prettierrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"printWidth": 115,
2+
"printWidth": 80,
33
"semi": false,
44
"singleQuote": false,
55
"bracketSpacing": true,

.vscode/settings.json

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
{
2-
"editor.quickSuggestions": false,
2+
"editor.quickSuggestions": {
3+
"comments": "off",
4+
"strings": "off",
5+
"other": "off"
6+
},
37
"files.exclude": {
48
"**/.git": true,
59
".sass-cache": true,
@@ -9,11 +13,15 @@
913
".bundle": true,
1014
"_gh-pages": true
1115
},
12-
"prettier.printWidth": 116,
16+
"prettier.printWidth": 80,
1317
"[markdown]": {
1418
"editor.formatOnSave": true,
1519
"editor.wordWrap": "on",
16-
"editor.quickSuggestions": false
20+
"editor.quickSuggestions": {
21+
"comments": "off",
22+
"strings": "off",
23+
"other": "off"
24+
}
1725
},
1826
"cSpell.words": [
1927
"APIs",
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
---
2+
layout: epic
3+
title: "Hacking Around Safari's 7-day Cookie Limit"
4+
subtitle: What we learned while trying to fix our cookie consent banner
5+
date: 2022-08-23
6+
categories: [Safari Cookies Consent Banner]
7+
author: [chris]
8+
---
9+
10+
Amongst the many, many things that organizations have to contend with around
11+
cookie consent laws is Apple's very own Safari. Did you know that Safari will
12+
only persist client-side cookies for 7 days? This is in support of Apple's
13+
[Intelligent Tracking Prevention (ITP)](https://clearcode.cc/blog/intelligent-tracking-prevention-faq),
14+
designed to improve user privacy.
15+
16+
These privacy efforts are great for users, but in hand with laws like the
17+
[GDPR](https://gdpr-info.eu/) and [CCPA](https://oag.ca.gov/privacy/ccpa) they
18+
create a UX nightmare for users. Here at Artsy we've landed on a way to make
19+
things slightly less bad and want to share our approach.
20+
21+
<!-- more -->
22+
23+
Scenario: Imagine you're a resident of the EU and visit Artsy.net for the first
24+
time. A banner appears asking you to `Accept` or `Deny` tracking cookies from
25+
our site. You don't like tracking cookies, so you click the 'Deny' button and
26+
the banner disappears. All good, right? Nope! You visit Artsy a week later and
27+
again, a banner appears asking you about your preference. This happens again and
28+
again until you switch browsers and realize that what you were just experiencing
29+
was Apple's ITP in action; even though you've rejected tracking cookies, the
30+
cookie we've used to store your preferences is erased after 7 days,
31+
necessitating another interaction.
32+
33+
While pondering how to work around this UX issue we landed on a pretty simple
34+
solution, prompted by a comment from a Safari Engineer we were able schedule a
35+
conference call with. She mentioned that the 7-day cookie limitation only
36+
applies to _client-side cookies_, and that **same-domain, secure, server-side
37+
cookies aren't limited to these constraints**.
38+
39+
This got us thinking. Our 3rd party cookie-consent management service sets a
40+
client-side cookie, not a server-side cookie. Could we perhaps "hijack" the
41+
client-side cookie with a server-side cookie _of the same name_ and trick safari
42+
into persisting the user preferences across the 7-day limit?
43+
44+
We gave it a try and... Yes. We. Can! And this means that you can too. (And it's
45+
also real easy to implement.)
46+
47+
---
48+
49+
First, define a server-side endpoint:
50+
51+
```tsx
52+
const app = express()
53+
54+
app.get("/set-tracking-preferences", (req, res) => {
55+
const { trackingPreferences } = req.query
56+
57+
const cookieConfig = {
58+
maxAge: 10000000,
59+
httpOnly: false,
60+
secure: true, // important!
61+
}
62+
63+
if (trackingPreferences !== "undefined") {
64+
// Overwrite client-side cookie with cloned, secure server-side version
65+
res.cookie("trackingPreferences", trackingPreferences, cookieConfig)
66+
}
67+
68+
res.send("Tracking preferences set.")
69+
})
70+
```
71+
72+
Next, call the server-side endpoint from the client when your app boots or when
73+
the preferences have been set by the user:
74+
75+
```tsx
76+
import cookies from "cookies-js"
77+
78+
const App = () => {
79+
useEffect(() => {
80+
const trackingPreferences = encodeURIComponent(cookies.get("trackingPreferences"))
81+
82+
fetch(
83+
`/set-tracking-preferences?trackingPreferences=${trackingPreferences}`
84+
)
85+
}, [])
86+
87+
return <CookieConsentBanner onClick={...} />
88+
}
89+
```
90+
91+
And that's it. While I'm not sure of the exact reason why we can overwrite
92+
cookies in this way, I suspect it has to do with Safari's assumption that a
93+
server we control will always take precedence thus assumes things are safe. And
94+
in seven days, when Safari returns to erase the cookie, it will see that it's
95+
now `secure` and will ignore, preserving the user's preferences.

0 commit comments

Comments
 (0)