Open DevTools → Application → Storage → Cookies to inspect.
Here’s a practical, beginner-friendly guide to using cookies to track simple state (like the user’s OS) on a basic HTML+JS site.
Concepts first: what cookies are and when to use them
A cookie is a small key=value string stored by the browser, scoped to a domain and path.
Browsers automatically send relevant cookies back to your server with every HTTP request. This is the main reason to choose cookies over other storage APIs.
If you don’t need the server to know something (like the user’s OS for purely client-side behavior), localStorage or sessionStorage are simpler because they don’t leave the browser. But learning cookies is useful and still common.
Key cookie attributes you should know
Expiration: no expiration means a session cookie (cleared when the browser is closed). Set an expiration with either:
Max-Age=SECONDS (preferred, relative)
Expires=DATE (absolute date string)
Path/Domain: determine where the cookie is visible. Use Path=/ to make it available across your whole site.
Secure: only send the cookie over HTTPS. Use this in production on HTTPS sites.
SameSite: controls cross-site sending. For most first-party use, SameSite=Lax is fine.
HttpOnly: prevents JS access. You cannot set this from JS. Use it on server-set cookies that JS shouldn’t read.
Basic cookie utilities in JS
You set cookies by assigning to document.cookie. Reading requires
parsing the cookie string. Use helpers.
[JS code]
Setting the OS cookie and using it
First visit: detect the OS, store it in a cookie.
Subsequent visits: read the cookie and branch your behavior/UI accordingly.
A note on modern OS detection
User-Agent strings are being reduced over time. Where available, you can use User-Agent Client Hints via navigator.userAgentData for better reliability. It’s asynchronous, so structure your code to await it, then set the cookie.
Example (progressive enhancement):
```
async function detectOSAsync() {
if (navigator.userAgentData?.getHighEntropyValues) {
try {
const data = await navigator.userAgentData.getHighEntropyValues(['platform']);
const p = (data.platform || '').toLowerCase();
if (p.includes('mac')) return 'mac';
if (p.includes('win')) return 'windows';
} catch {}
}
return detectOS(); // fallback to the sync version above
}
(async () => {
let os = getCookie('os');
if (!os) {
os = await detectOSAsync();
setCookie('os', os, { maxAge: 31536000, path: '/', sameSite: 'Lax' });
}
applyOsBehavior(os);
})();
```
How cookies differ from localStorage (and when to choose which)
Cookies:
Sent to the server automatically on matching requests (good for server-side customization).
Limited in size (~4KB per cookie; per-domain limits apply).
Have attributes for security and scoping.
localStorage/sessionStorage:
Client-only; never sent to your server automatically.
Simpler API (localStorage.setItem/getItem).
Larger quotas than cookies.
If you only need client-side behavior and have a purely static site, localStorage can be simpler. If you might do server-side rendering or logs that vary by OS, the cookie is useful.
Debugging tips
Open your browser’s DevTools → Application (or Storage) → Cookies to view, edit, and delete cookies.
On the Network tab, click a request and check the Request Headers to see which cookies are sent.
Remember that cookies are scoped. If you forget Path=/, your cookie might not be visible across your site.
Security and privacy notes
Use Secure on HTTPS sites so cookies aren’t sent over HTTP.
Don’t put sensitive data in JS-accessible cookies.
For cross-site use (e.g., in an embedded iframe) you may need SameSite=None; Secure.
Consider user consent and privacy policies when storing identifiers. An OS cookie used solely for UX is generally low risk, but follow your local regulations.
That’s the core workflow: detect → store → read → branch your UI/logic. With the helpers above, you can extend to other state (e.g., feature flags, dismissed banners) by adding more cookie keys.