Real Client IP with @sentry/nextjs tunnel?

Hey all,

What’s the right way to pass the real client-side IP when using @sentry/nextjs@6.13.3's tunnel option?

I’m using the example Next.js tunnel implementation; however, the user IP reflected in Sentry UI is that of the backend server, not of the client.

I have also tried forwarding req.headers['x-forwarded-for'] || req.socket.remoteAddr as X-Forwarded-For to the /envelope endpoint. The resulting X-Forwarded-For header I’m sending contains the real client IP in the first position. However, that doesn’t seem to change its behaviour at all, Sentry UI still shows the IP of the backend server as the user IP.

Looks like I found a workaround. Adding forwarded_for: "<real-ip>" into the envelope header results in Sentry UI displaying the correct client IP.

I would appreciate it if any Sentry folks could offer a less hacky way to do this or confirm that this is indeed the intended way to do it.

Here’s roughly what my code looks like for that:

    const envelope = req.body;
    const [rawHeader, ...restPieces] = envelope.split('\n');

    const header = JSON.parse(rawHeader);

    // omitted: check DSN, host, project ID

    const body = [
      // HACK: Attempt to communicate the real client IP address to Sentry.
      //       The `forwarded_for` field was deduced from a test in Sentry's
      //       Relay (server) handling of the Envelope format,
      //       cf.
          typeof req.headers['x-forwarded-for'] === 'string'
            ? req.headers['x-forwarded-for']
            : req.socket.remoteAddress,

    const url = `https://${sentryHost}/api/${projectId}/envelope/`;
    const response = await fetch(url, {
      method: 'POST',

The existence of this field was deduced from a Relay test here: relay/ at 2e924639d7bcfa24db69ba2ed78a82e2c07478e1 · getsentry/relay · GitHub

1 Like

Is this still working for you? I tried to take the same route, but getting a 401 coming back from Sentry, with error / response body of -

    "detail": "missing authorization information"

Assuming this is because it can’t parse the DSN info out of the JSON any longer, not sure?

Still works fine for us.

1 Like

Thanks for response! It ended up being an error w/ the final POST call itself (body wasn’t getting set correctly), which is why my earlier logging wasn’t seeing anything wrong w/ formatting.