HTTP Headers: Cookie Request Header Deep Dive (2026)

I still remember the day a single missing cookie header turned a “working” login into a production outage. Sessions were created, users were authenticated, and yet every subsequent request was treated as anonymous. The culprit wasn’t the server logic—it was a subtle mismatch between how the browser sent cookies and how our edge cache varied responses. That experience changed how I teach and review HTTP cookie behavior. If you work on APIs, web apps, or edge infrastructure, you should treat the Cookie request header as a first-class part of your design, not a background detail.

You’ll walk away knowing exactly how the Cookie header is formatted, how it interacts with Set-Cookie, and why modern privacy controls and security flags shape what you actually receive on the server. I’ll show concrete, runnable examples, give you practical rules for when to use cookies and when to avoid them, and tie everything into 2026-era tooling so you can diagnose problems fast. This is the kind of boring-looking header that, in practice, decides whether your authentication, personalization, and security posture really work.

The Cookie Request Header: What It Is and Why It Matters

The Cookie header is an HTTP request header that your browser sends back to a server. It’s the carrier for state—session IDs, preferences, CSRF tokens, and other data the server previously set via one or more Set-Cookie response headers. In other words, Set-Cookie is the server’s output, and Cookie is the browser’s input on the next request.

The syntax is deceptively simple:

Cookie: name=value

Multiple cookies are sent as a semicolon-separated list:

Cookie: name=value; name=value; name=value

In practice, a real request might look like:

Cookie: sessionId=7c3a7f...; theme=dark; csrftoken=8e1d2c...

Here’s the key idea I want you to keep in mind: the server does not receive cookies unless the browser chooses to send them. That decision is influenced by cookie attributes (like Path, Domain, Secure, and SameSite), by the browser’s privacy model, and by the request context (top-level navigation vs. subresource, same-site vs. cross-site). The header is just the final output of that decision. When you troubleshoot issues, you’re debugging the decision-making pipeline, not just the header itself.

From Set-Cookie to Cookie: The Round-Trip Mental Model

I always model cookies as a round-trip:

1) The server responds with Set-Cookie.

2) The browser stores the cookie if it passes rules.

3) The browser decides whether to send it on a future request.

4) The server reads the Cookie header and makes decisions.

If any part of that chain breaks, you’ll see missing cookies, duplicated cookies, or outdated values. Here’s a minimal example with an HTTP server in Node.js and a client request showing the header.

// server.js

import http from "http";

const server = http.createServer((req, res) => {

if (req.url === "/login") {

// Set a session cookie after "login"

res.setHeader("Set-Cookie", "sessionId=abc123; Path=/; HttpOnly; Secure; SameSite=Lax");

res.writeHead(200, { "Content-Type": "text/plain" });

res.end("Logged in\n");

return;

}

// Read incoming Cookie header

const cookieHeader = req.headers.cookie || "";

res.writeHead(200, { "Content-Type": "text/plain" });

res.end(Cookie header received: ${cookieHeader}\n);

});

server.listen(3000, () => {

console.log("Server running at http://localhost:3000");

});

Try this flow in your terminal:

node server.js

curl -i http://localhost:3000/login

curl -i --cookie "sessionId=abc123" http://localhost:3000/

This example highlights two real-world truths: the server never sees cookies unless the client sends them, and any custom client (like curl, mobile apps, or server-to-server calls) must explicitly attach them. If you build APIs for multiple clients, you should define a cookie strategy or use a token-based alternative for non-browser clients.

Parsing Cookies Safely and Predictably

On the server, you’ll almost always need to parse the Cookie header into a structured object. I’ve seen teams hand-roll parsing logic that breaks on whitespace, URL-encoded values, or duplicate cookie names. My rule: use a well-maintained parser and standardize behavior across services.

Here’s a simple Express example with the cookie-parser middleware:

// app.js

import express from "express";

import cookieParser from "cookie-parser";

const app = express();

app.use(cookieParser());

app.get("/profile", (req, res) => {

const sessionId = req.cookies.sessionId;

if (!sessionId) {

return res.status(401).json({ error: "Missing session" });

}

res.json({ message: "Session found", sessionId });

});

app.listen(3001, () => console.log("Server on 3001"));

If you’re in Python, http.cookies.SimpleCookie handles parsing, but I still recommend centralizing logic to avoid subtle inconsistencies between microservices.

# server.py

from http.server import BaseHTTPRequestHandler, HTTPServer

from http.cookies import SimpleCookie

class Handler(BaseHTTPRequestHandler):

def do_GET(self):

cookie_header = self.headers.get("Cookie", "")

cookie = SimpleCookie()

cookie.load(cookie_header)

session_id = cookie.get("sessionId")

if session_id is None:

self.send_response(401)

self.end_headers()

self.wfile.write(b"Missing session")

return

self.send_response(200)

self.end_headers()

self.wfile.write(f"Session: {session_id.value}".encode())

HTTPServer(("localhost", 3002), Handler).serve_forever()

Parsing is a security boundary. If you do anything custom, add tests for:

  • whitespace around ;
  • URL-encoded values
  • multiple cookies with same name (browsers usually send the most recent, but behavior can vary)
  • unexpected control characters

Security Flags That Decide What You Receive

Most bugs I diagnose come from confusing cookie attributes with cookie payload. Attributes are not in the Cookie header itself; they’re set in Set-Cookie and only influence whether the browser sends the cookie back. These are the attributes that matter most in 2026:

  • HttpOnly: Blocks JavaScript access. This reduces XSS risk but makes client-side debugging harder.
  • Secure: Cookie only sent over HTTPS. If you test on http:// you won’t see it.
  • SameSite: Controls cross-site sending. In modern browsers, Lax is the default and None requires Secure.
  • Path/Domain: Scope the cookie to URLs and subdomains.

Example Set-Cookie for a session:

Set-Cookie: sessionId=abc123; Path=/; HttpOnly; Secure; SameSite=Lax

A cookie with SameSite=Strict will not be sent on cross-site requests. This can break third-party auth callbacks, embedded widgets, and some payment flows. I always recommend testing cookies in the exact request context they will be used: top-level navigation, subresource, iframe, API fetch, and cross-site redirects.

A practical test matrix

I keep a matrix like this when debugging:

  • Same-site top-level navigation → Should include Lax and Strict
  • Cross-site top-level navigation → Lax often included; Strict excluded
  • Cross-site subresource (image, iframe, fetch) → Lax excluded; None may be included if Secure
  • Non-HTTPS → Secure excluded

If your product relies on cross-site cookies, you need to plan for user privacy features and the gradual tightening of browser policies. Build a fallback for token-based auth in those flows.

The Exact Wire Format: What Gets Sent and What Doesn’t

It’s worth being precise about what goes over the wire. In Set-Cookie, you specify attributes like Path, Domain, Expires, Max-Age, SameSite, HttpOnly, and Secure. But in the Cookie header, only name/value pairs are sent, and they are separated by semicolons.

That means if you see:

Set-Cookie: sessionId=abc123; Path=/; Secure; HttpOnly; SameSite=Lax

You will later receive only:

Cookie: sessionId=abc123

Those attributes are not repeated. They are memory inside the browser. This is why you cannot rely on the Cookie header to learn the policy of a cookie. If your server needs to enforce a policy (like “this cookie must have been Secure”), enforce that at issuance and store server-side metadata that you can check later.

Subtle formatting edge cases

Real browsers and proxies can differ in spacing or ordering:

  • Some add a space after ;, others don’t.
  • Ordering is not guaranteed across implementations.
  • If duplicate cookie names exist, the order is usually path-length order, but you should not rely on it.

That’s why robust parsing is a must and why you should never assume a cookie list is “stable.” Your server must be resilient to disorder and duplicates.

Cookie Size Limits and Chunking Behavior

Cookies are small by design. The exact limit varies by browser, but you should not rely on more than a few kilobytes per cookie, and a few dozen cookies per domain. Exceeding limits leads to silent drops or partial data, which makes debugging painful.

Practical rules I use:

  • Keep individual cookies under 1 KB whenever possible.
  • Keep the total cookie header under 4–8 KB for safety.
  • Prefer server-side state if you need lots of data.

I’ve seen teams “chunk” large values into multiple cookies (e.g., prefspart1, prefspart2) and reassemble them server-side. That can work, but it increases overhead, increases failure modes, and can trigger subtle browser limits. I reserve chunking for short-lived migration windows, not for permanent architectures.

Cookie Path and Domain Scope: The Hidden Footguns

Path and Domain determine when a cookie is included. This sounds simple until you deal with multiple services or micro-frontends.

  • Path=/ means “send on every request.”
  • Path=/auth means “send only for /auth and deeper.”
  • Domain=example.com means “send for example.com and subdomains.”
  • Domain=auth.example.com means “send only for that subdomain.”

Mistakes I see most:

  • Setting a narrow path and then wondering why the API doesn’t see the cookie.
  • Setting a domain too wide and unintentionally leaking cookies to unrelated apps on subdomains.
  • Running in development on localhost and expecting domain rules to behave exactly like production.

My pattern is to keep session cookies scoped to the app domain, not the apex, unless I specifically need single sign-on across subdomains. If you do need cross-subdomain access, be explicit and document why the broader domain is safe.

Cookie vs. Authorization Header: A Clearer Mental Model

People often compare cookies to Authorization headers, but the deeper difference is who decides when it is sent. Cookies are browser-managed and can be sent automatically. Authorization headers are client-managed and must be explicitly added.

I think of it like this:

  • Cookies are for the browser doing work on your behalf.
  • Authorization headers are for clients explicitly vouching for a token on each request.

This distinction matters for CSRF. Because cookies are sent automatically, the browser will attach them even to cross-site requests (depending on SameSite). That’s why CSRF exists. With explicit tokens in headers, CSRF risk is lower because the attacker cannot set your headers. That’s not a universal rule, but it’s a strong default intuition.

Hybrid model I recommend

  • Use cookies for primary web sessions.
  • Use explicit tokens for API clients, mobile apps, and partner integrations.
  • If you share endpoints between browser and non-browser clients, accept both and keep server policy consistent.

This hybrid model is boring, but it’s reliable. It gives the browser a seamless UX while keeping API contracts explicit and testable.

When to Use Cookies vs. Other Options

You shouldn’t use cookies for everything. Here’s how I decide, with a clear recommendation instead of hand-waving.

Use cookies when:

  • You need browser-managed session state
  • You need automatic sending on relevant requests
  • You want HttpOnly protection for session identifiers
  • You need compatibility with old HTTP clients

Don’t use cookies when:

  • You’re building non-browser APIs (mobile apps, IoT, server-to-server)
  • You need large payloads or complex nested data
  • You need explicit, per-request control from the client
  • You need clear audit trails for auth state per request

Here’s the comparison in a table, with a 2026 tilt toward explicit, verifiable auth:

Decision

Traditional Cookie Session

Modern Token Header —

— Primary use

Browser sessions

API-first auth flows Client control

Low (auto-sent)

High (explicit) XSS exposure

Lower with HttpOnly

Higher if stored in JS CSRF risk

Higher if cookies auto-sent

Lower with explicit token Debuggability

Medium

High Best for

Web apps with browser-only clients

Mobile, server-to-server, mixed clients

My recommendation: use cookies for browser sessions and identity, but pair them with explicit tokens for API clients and integration workflows. That hybrid approach avoids forcing every client into browser-centric patterns.

Common Mistakes I Still See (And How You Avoid Them)

1) Expecting cookies on cross-site fetch requests

If you call fetch from one domain to another, cookies won’t be sent unless you set credentials: "include" and the server allows it with proper CORS headers. The server also needs Access-Control-Allow-Credentials: true.

// Browser client

fetch("https://api.example.com/user", {

method: "GET",

credentials: "include",

})

2) Setting SameSite=None without Secure

Modern browsers reject it. You’ll see the cookie in the response but never in the request header.

3) Using cookies for large JSON payloads

Cookies are small and sent on every request. They bloat traffic and slow down every page. Keep them lean—IDs and minimal flags only.

4) Forgetting the Path scope

If you set Path=/auth, you won’t see the cookie on /api. Use / unless you really want isolation.

5) Blindly trusting a cookie value

Always treat cookies as untrusted input. Validate and verify server-side, and never store sensitive data in cleartext cookies.

Cross-Site Requests, CORS, and Cookies: The Three-Body Problem

The interplay between cookies, CORS, and fetch is the single most common source of “missing cookie” bugs I see.

The rules you must internalize

  • For cross-site fetch, the browser will not include cookies unless credentials: "include" is set.
  • The server must respond with Access-Control-Allow-Credentials: true.
  • The server must not use Access-Control-Allow-Origin: * if it allows credentials. It must echo an explicit origin.
  • The cookie must be allowed by SameSite rules, and Secure if SameSite=None.

Here’s a simple Express CORS configuration that supports credentialed requests:

import express from "express";

import cors from "cors";

const app = express();

app.use(cors({

origin: "https://app.example.com",

credentials: true,

}));

app.get("/me", (req, res) => {

const cookie = req.headers.cookie || "";

res.json({ cookie });

});

If you don’t control both client and server, be cautious. CORS misconfigurations are a common security risk. I always test cross-site cookies with a dedicated integration test or scripted browser session to avoid silent misbehavior.

Session Cookies vs. Persistent Cookies

One subtle point that affects user experience and security: cookies can be session-only or persistent.

  • Session cookies are cleared when the browser is closed.
  • Persistent cookies have an explicit Expires or Max-Age and survive restarts.

I default to session cookies for security unless a product requirement clearly demands persistence (like “remember me”). When you do use persistent cookies, set a reasonable max age and rotate identifiers periodically.

Practical strategy

  • Issue a short-lived session cookie.
  • If the user selects “remember me,” issue a long-lived refresh cookie with a separate identifier.
  • Keep the long-lived cookie HttpOnly and Secure.
  • Store refresh tokens server-side with revocation support.

This model keeps your session surface small while still offering convenience.

Real-World Scenarios and Edge Cases

Edge caching and Vary behavior

When you introduce CDNs or edge caching, you must think about whether responses vary based on cookies. If your HTML changes by user session, you either disable caching or you set Vary: Cookie and accept lower cache efficiency. Many systems instead move personalization to a secondary API request, allowing the main HTML to be cached. That’s the pattern I use for large sites.

Multi-subdomain authentication

If you authenticate on auth.example.com but want access on app.example.com, you must set Domain=.example.com. Remember: the leading dot is optional in modern specs, but you should test cross-subdomain behavior carefully.

Duplicate cookie names

Browsers can send multiple cookies with the same name if they differ by Path or Domain. The server library you choose decides which one “wins.” To avoid ambiguity, keep names unique across the domain tree or explicitly namespace them.

Clock skew and session expiry

If you store expiry timestamps in cookies, compare them with server time, not client time. Clients are unreliable, and time drift can create false session expiry. Prefer server-side expiration with a short session ID and revocation list.

The “two cookies, one request” trap

If you set a cookie twice with the same name but different paths, you might receive two values in the same request. Some libraries pick the first, some pick the last, and some give you both. This is why I avoid path-scoped cookies unless I absolutely need them.

Performance Considerations You Can Actually Measure

Cookies travel with every request to a matching domain and path. This adds overhead to each request and can show up in real metrics. The cost is small per request but large at scale.

Typical impact ranges I see in practice:

  • Extra header bytes: 300–1500 bytes per request for common session cookies
  • Latency impact: typically 1–5 ms per request on low-latency networks; 10–15 ms on higher-latency mobile links
  • Cache fragmentation: significant if you vary on cookies across a large user base

If you’re performance-sensitive, keep cookies short. I aim for session IDs under 64 bytes and avoid storing user preferences in cookies when I can place them in local storage or server-side profiles.

A quick back-of-the-envelope calculation

If you have 100 million requests per day and each request includes 800 bytes of cookies, that’s ~80 GB of additional data just in headers. That might not kill you, but it’s wasted bandwidth you pay for and your users feel. This is why I ruthlessly prune cookie payloads during performance audits.

Designing Cookie Schemas That Scale

Cookie names, values, and scopes form a “schema,” even if you didn’t call it that. Poor naming and inconsistent behavior create chaos as products grow.

My rules:

  • Use a single prefix for app cookies, e.g., appsession, apppref_theme.
  • Avoid reusing names across multiple projects in the same domain.
  • Keep values opaque. If you need metadata, store it server-side.
  • Document which cookies are expected on which endpoints.

If you want a clean approach, define a small contract like:

  • app_session: short opaque ID, HttpOnly, Secure, SameSite=Lax, Path=/
  • app_csrf: short random token, not HttpOnly (if you need JS), SameSite=Lax
  • app_pref: minimal preferences, short-lived, optional

Then enforce it with tests or middleware.

Cookie Security Beyond Flags

Flags are necessary but not sufficient. You also need to think about how cookies are generated, stored, rotated, and invalidated.

Rotation and revocation

If you only store a session ID in a cookie, your server-side session store becomes the enforcement point. That’s good. But it also means you need a revocation strategy: delete the session server-side and ensure the cookie becomes useless.

I rotate session IDs after:

  • login
  • privilege escalation
  • sensitive user actions (e.g., password change)

Rotation reduces fixation risk and gives you a clean audit trail.

Signing vs. encryption

Some frameworks sign cookies so they can store data client-side. This can be fine for non-sensitive data, but it still exposes the contents to the user. If you must store data in cookies, either sign and encrypt or avoid putting anything sensitive in the first place. I default to opaque IDs + server-side storage because it’s simpler and safer.

Debugging Workflow in 2026: What I Actually Do

In 2026, I rely on a mix of classic tools and AI-assisted workflows. The basics still matter:

  • Browser DevTools: Inspect request headers and response Set-Cookie values.
  • HTTP proxies: Capture full request/response pairs to see the round-trip.
  • Server logs: Log the raw Cookie header on auth failures (redacted) for fast triage.

The modern additions:

  • AI log summarizers: Use an assistant to scan for “cookie missing” patterns, but always inspect raw samples.
  • Automated test sandboxes: I run a scripted browser test that asserts cookie behavior across navigation types and subresource requests.
  • Security policy linters: I run a small static check on Set-Cookie flags to ensure Secure and HttpOnly on session cookies.

Here’s a quick example using Playwright to verify that a cookie is sent only on same-site requests:

// cookie-test.js

import { chromium } from "playwright";

(async () => {

const browser = await chromium.launch();

const page = await browser.newPage();

// Pretend we already have a cookie set by the server

await page.context().addCookies([

{

name: "sessionId",

value: "abc123",

domain: "localhost",

path: "/",

httpOnly: true,

sameSite: "Lax",

},

]);

const response = await page.goto("http://localhost:3001/profile");

console.log("Status:", response.status());

await browser.close();

})();

This type of test catches issues early, especially when refactoring auth flows or changing domain routing.

Practical Guidelines I Recommend

When I review cookie implementations, I look for these patterns:

  • Session cookies: HttpOnly; Secure; SameSite=Lax; Path=/
  • Cross-site cookies (only if necessary): SameSite=None; Secure
  • Minimal payload: only IDs or short flags
  • Centralized parsing: one library, one behavior
  • Clear expiration strategy: session lifetime in server storage

If you’re building a new product, start with cookies for browser sessions, then add explicit Authorization headers for API clients. This keeps the browser flow smooth while giving non-browser clients a reliable, debuggable contract.

Cookie Behavior in Frameworks: Hidden Defaults

Frameworks can change cookie behavior in ways that surprise people. Some set SameSite=Lax by default, others do not. Some auto-add Secure when they detect HTTPS; others require explicit configuration.

I always do a “header audit” after setting up auth in a framework:

1) Inspect the exact Set-Cookie headers being sent.

2) Confirm that every security flag is present for session cookies.

3) Validate the cookies are received in the contexts you expect.

If you skip this audit, you are trusting framework defaults you didn’t verify, and that’s how most auth regressions happen.

Designing for Privacy Changes and Deprecations

Browser privacy changes are not hypothetical anymore. Cross-site cookies are restricted, partitioned, or blocked in more contexts every year. That means “it works now” might not mean “it works in two quarters.”

My general strategy is:

  • Avoid reliance on third-party cookies wherever possible.
  • Use same-site patterns for authentication and user state.
  • Build fallbacks for embedded experiences and federated flows.

If you must do cross-site cookies, accept that some users will be blocked and build a resilient UX path for those users (e.g., redirect to top-level navigation, use explicit token exchange, or prompt for re-authentication).

Observability: What to Log (and What Not To)

Cookies are sensitive. Logging them verbatim is risky. But you still need visibility.

I recommend:

  • Log whether the cookie exists, not the full value.
  • Log a hash or truncated prefix for correlation.
  • Redact sensitive cookies by name.
  • Use structured logs so you can filter by cookie presence.

Example pattern:

  • cookie.session.present = true
  • cookie.session.prefix = "7c3a7f"
  • cookie.csrf.present = false

This gives you enough signal without exposing secrets.

Alternative Approaches for Stateful Web Apps

Cookies are not the only option, and sometimes they’re not the best. Here are practical alternatives and when they fit:

  • Authorization headers with bearer tokens: Best for API clients and SPAs that can securely store tokens.
  • Signed JWTs in cookies: Works, but risks token leakage and has revocation complexity.
  • Server-side sessions + one-time tokens: Great for high-security flows, but more complex.
  • Local storage with tokens: Easy but higher XSS risk; use only if you have strong XSS protection.

I still prefer server-side session IDs in HttpOnly cookies for browser apps. It’s the simplest reliable pattern with the least exposure to front-end compromise.

A Deeper Example: Full Login Flow with Rotation

Here’s a more complete Node.js example showing login, session rotation, and logout with careful cookie handling.

// auth-server.js

import express from "express";

import cookieParser from "cookie-parser";

import crypto from "crypto";

const app = express();

app.use(express.json());

app.use(cookieParser());

const sessions = new Map();

function newSessionId() {

return crypto.randomBytes(24).toString("hex");

}

function setSessionCookie(res, sessionId) {

res.setHeader("Set-Cookie", sessionId=${sessionId}; Path=/; HttpOnly; Secure; SameSite=Lax);

}

app.post("/login", (req, res) => {

const { username } = req.body || {};

if (!username) return res.status(400).json({ error: "Missing username" });

const sessionId = newSessionId();

sessions.set(sessionId, { username, createdAt: Date.now() });

setSessionCookie(res, sessionId);

res.json({ ok: true });

});

app.post("/rotate", (req, res) => {

const sessionId = req.cookies.sessionId;

if (!sessionId || !sessions.has(sessionId)) {

return res.status(401).json({ error: "Missing session" });

}

sessions.delete(sessionId);

const newId = newSessionId();

sessions.set(newId, { username: "unknown", createdAt: Date.now() });

setSessionCookie(res, newId);

res.json({ ok: true });

});

app.post("/logout", (req, res) => {

const sessionId = req.cookies.sessionId;

if (sessionId) sessions.delete(sessionId);

res.setHeader("Set-Cookie", "sessionId=; Path=/; Max-Age=0; HttpOnly; Secure; SameSite=Lax");

res.json({ ok: true });

});

app.get("/me", (req, res) => {

const sessionId = req.cookies.sessionId;

const session = sessionId ? sessions.get(sessionId) : null;

if (!session) return res.status(401).json({ error: "Not authenticated" });

res.json({ user: session.username });

});

app.listen(3003, () => console.log("Auth server on 3003"));

This example shows the pattern I use in real systems: short session IDs, server-side storage, explicit rotation, and clear logout behavior.

Testing Checklist I Actually Use

Before I ship a cookie-based auth system, I walk through a checklist like this:

  • Set-Cookie includes HttpOnly, Secure, and SameSite for session cookies.
  • Cookies are sent on same-site navigation requests.
  • Cookies are not sent when they shouldn’t be (cross-site subresource, non-HTTPS).
  • CORS with credentials is configured and tested (if needed).
  • Duplicate cookie names are avoided.
  • Logout clears the cookie and the server-side session.
  • Session rotation works and old sessions are invalidated.
  • All cookie values are short and opaque.

If any item fails, I don’t ship. It’s cheaper to fix now than in production.

Key Takeaways and What You Should Do Next

If there’s one thing I want you to remember, it’s that the Cookie request header is not a simple key-value list—it’s the end result of browser policy, security flags, request context, and user privacy settings. When I build or review auth systems, I treat cookie behavior as part of the core architecture, not a detail to patch later.

You should start by auditing which requests actually need cookies, then verify that your Set-Cookie flags match the contexts where cookies must be sent. If you rely on cross-site flows, test them explicitly, and plan for a future where those flows may be increasingly restricted. Cookies are still a core part of the web, but they are not a free pass—you have to design for them with intent.

If you want a fast, practical next step, do this today:

  • Inspect your production Set-Cookie headers.
  • Confirm Secure and HttpOnly on every session cookie.
  • Check that your app still works with SameSite=Lax defaults.
  • Run a single cross-site fetch test with credentials: "include" and confirm the server sees the cookie.

That short audit catches most cookie bugs before they become outages.

Scroll to Top