Where Are Nitter User Preferences Stored? Cookie-Based Configuration Explained
Nitter stores user preferences in HTTP cookies using the savePref template in src/routes/router_utils.nim, with fallback defaults generated from the configuration file via the genDefaultPrefs macro in src/prefs_impl.nim.
Nitter is a privacy-focused front-end for Twitter/X that operates without user accounts. When visitors toggle settings like themes, autoplay, or infinite scroll, those choices must persist across page loads. According to the zedeus/nitter source code, the application implements a three-tier preference hierarchy centered on browser cookies rather than server-side databases.
How Nitter Stores Preferences
Unlike traditional web applications that persist settings in a database tied to user accounts, Nitter leverages the browser's cookie storage to maintain state anonymously. This approach aligns with the project's privacy-focused architecture.
The Cookie-Based Architecture
Nitter writes preference changes to HTTP cookies immediately when a user modifies a setting. The savePref template in src/routes/router_utils.nim handles this operation, setting cookies with specific security flags including httpOnly, secure, and sameSite attributes based on the instance's HTTPS configuration.
When a request arrives, the requestPrefs template (also in src/routes/router_utils.nim) reads these cookies and constructs a Prefs object. This object represents the complete configuration state for that specific visitor.
Configuration-Driven Defaults
If no cookies exist for a particular preference, Nitter falls back to default values compiled from the instance configuration. The genDefaultPrefs macro in src/prefs_impl.nim generates these defaults from the nitter.example.conf file, ensuring every instance can customize its baseline user experience.
Reading and Writing Preference Cookies
The preference system relies on two complementary operations: persisting changes to cookies and reconstructing the preference state on each request.
Writing Cookies with savePref
The savePref template writes individual preferences as separate cookies with a 360-day expiration period (or immediate expiration when clearing). The implementation includes security hardening appropriate to the transport protocol:
# src/routes/router_utils.nim
template savePref*(pref, value: string; req: Request; expire = false) =
setCookie(pref, value,
daysForward(when expire: -10 else: 360),
httpOnly = true, secure = cfg.useHttps,
sameSite = if cfg.useHttps: None else: Lax,
path = "/")
This template sets httpOnly to prevent JavaScript access, respects the instance's HTTPS settings for the secure flag, and applies sameSite policies to mitigate CSRF attacks.
Reading Cookies with getPrefs
On each request, the getPrefs procedure in src/prefs.nim reconstructs the user's configuration by layering cookie values over the defaults:
# src/prefs.nim
proc getPrefs*(cookies, params: Table[string, string]): Prefs =
result = defaultPrefs # defaults from config
genParsePrefs(cookies) # overlay cookie values
genParsePrefs(params) # overlay URL "prefs" values
This procedure first populates the result with defaultPrefs (generated by the configuration macro), then overlays values from cookies, and finally applies any URL parameters for temporary overrides.
The Preference Resolution Hierarchy
Nitter resolves preferences through a specific priority chain, allowing flexible configuration while maintaining user agency.
URL Parameter Overrides
The system supports temporary preference changes via the prefs query parameter. The applyUrlPrefs mechanism (invoked through genParsePrefs) parses these parameters and overlays them on top of cookie values. This allows users to share links with specific viewing configurations without altering their saved preferences.
Macro-Generated Defaults and Encoding
The genDefaultPrefs macro in src/prefs_impl.nim transforms the configuration file into compile-time Nim code, while genEncodePrefs handles the reverse operation—converting a Prefs object back into a query string for URL sharing:
# src/prefs_impl.nim
macro genEncodePrefs*(prefs): untyped =
for pref in allPrefs():
when pref.kind == checkbox:
if prefs.`pref.name` != defaultPrefs.`pref.name`:
encPairs.add pref.name & "=" & (if prefs.`pref.name`: "on" else: "")
else:
if prefs.`pref.name` != defaultPrefs.`pref.name`:
encPairs.add pref.name & "=" & prefs.`pref.name`
This macro compares each preference against its default value, only encoding non-default settings to create clean, shareable URLs.
Summary
- Cookie Storage: Nitter persists user preferences in HTTP cookies via the
savePreftemplate insrc/routes/router_utils.nim, with 360-day expiration and security flags. - Default Generation: Built-in defaults originate from
nitter.example.confand compile into Nim code through thegenDefaultPrefsmacro insrc/prefs_impl.nim. - Resolution Order: The
getPrefsprocedure insrc/prefs.nimapplies configuration defaults first, then overlays cookie values, and finally processes URL parameters for temporary overrides. - Privacy Design: By avoiding server-side storage and using
httpOnlycookies, Nitter maintains its privacy-focused architecture without requiring user accounts.
Frequently Asked Questions
Are Nitter preferences stored server-side?
No. According to the zedeus/nitter source code, preferences are stored exclusively in browser cookies. The server maintains no database or session storage for individual user settings, aligning with Nitter's privacy-focused design that requires no user accounts.
How long do Nitter preference cookies last?
Preference cookies persist for 360 days by default, as defined in the savePref template in src/routes/router_utils.nim. When clearing preferences explicitly, the template sets an expiration of 10 days in the past to immediately invalidate the cookie.
Can I share Nitter preferences via URL?
Yes. The genEncodePrefs macro in src/prefs_impl.nim encodes non-default preferences into a prefs query parameter. When accessing a Nitter URL with this parameter, the getPrefs procedure applies these values as temporary overrides without modifying your stored cookie preferences.
Where are the default preference values defined?
Default values are defined in the nitter.example.conf configuration file. The genDefaultPrefs macro in src/prefs_impl.nim processes this file at compile time to generate the defaultPrefs constant used when no cookies are present.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →