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.

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 savePref template in src/routes/router_utils.nim, with 360-day expiration and security flags.
  • Default Generation: Built-in defaults originate from nitter.example.conf and compile into Nim code through the genDefaultPrefs macro in src/prefs_impl.nim.
  • Resolution Order: The getPrefs procedure in src/prefs.nim applies configuration defaults first, then overlays cookie values, and finally processes URL parameters for temporary overrides.
  • Privacy Design: By avoiding server-side storage and using httpOnly cookies, 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →