Skip to content

Pixel route /p/[slug] does not save events from email clients (Gmail, Thunderbird) #4028

@juanisidoro

Description

@juanisidoro

Bug: Pixel endpoint returns 200 but does not save events to database

The pixel endpoint /p/[slug] returns the 1x1 GIF correctly (HTTP 200) but does
not save the event to the database when loaded by email clients.

Steps to reproduce

  1. Create a pixel in Umami
  2. Embed it in an HTML email: <img src="https://your-umami/p/SLUG" width="1" height="1" />
  3. Send the email and open it from Gmail (mobile or web) or Thunderbird
  4. Check the pixel dashboard — no event is recorded

What I found

The issue is in src/app/(collect)/p/[slug]/route.ts. The handler creates a
new Request() and calls POST() from /api/send/route.ts internally:

const req = new Request(request.url, {
    method: 'POST',
    headers: request.headers,
    body: JSON.stringify(payload),
});
await POST(req);

But the POST handler calls getClientInfo(request, payload) which likely reads
the IP from the connection context, not from headers. Since the request is
constructed internally, the connection IP is lost or resolves to localhost,
causing the event to be silently dropped.

Proof

  • Calling POST /api/send directly with a pixel payload works and saves the event correctly.
  • Calling GET /p/[slug] from the same server with curl does NOT save the event, even with DISABLE_BOT_CHECK=1.
  • Nginx access logs confirm all requests arrive with HTTP 200 and the GIF is returned.
  • The database shows 0 events from email clients despite multiple confirmed requests.

Environment

  • Umami 3.0.3
  • PostgreSQL 16
  • Docker deployment behind Nginx reverse proxy
  • DISABLE_BOT_CHECK=1 enabled (issue persists regardless)

Database

PostgreSQL

Relevant log output

Nginx access logs show requests arriving correctly:

  66.249.93.195 - "GET /p/OZJpAdO8o HTTP/1.1" 200 43 "Mozilla/5.0 (via ggpht.com GoogleImageProxy)"
  84.125.169.180 - "GET /p/OZJpAdO8o HTTP/2.0" 200 43 "Thunderbird/143.0.1"

But database shows 0 events:

  SELECT count(*) FROM website_event WHERE url_path = '/p/OZJpAdO8o';
   count

   0

Direct POST to /api/send with same pixel ID works:

  curl -X POST /api/send -d '{"type":"event","payload":{"pixel":"","url":"..."}}'

Returns: {"cache":"...","sessionId":"...","visitId":"..."}

And event IS saved in database

Which Umami version are you using? (if relevant)

3.0.3

Which browser are you using? (if relevant)

Gmail (GoogleImageProxy), Thunderbird 143, Chrome 144

How are you deploying your application? (if relevant)

Docker (self-hosted, behind Nginx reverse proxy)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfixed in devFixed in the dev branch

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions