# Avoid adblockers with proxy

URL: https://pieowl.com/docs/adblockers



This page covers why ad blockers block analytics, how they do it, and how to avoid it.

Ad blockers started out blocking ads, but most now block tracking scripts too. That's mostly for privacy, and we respect it. Still, you have good reasons to understand your visitors. Pieowl sets no cookies and doesn't track people across sites, but generic blocklists often block every analytics tool the same way.

The best fix is to send events through your own domain. Ad blockers usually can't block requests to your own domain (first-party requests) without breaking the site itself.

Built-in support [#built-in-support]

`@pieowl/bots` has a ready-made proxy. It serves the tracking script at `<route>/pieowl.js`, passes on what the script should collect (`<route>/config/tracking`, from Settings → Site) and forwards events (`<route>/track`) to Pieowl with the visitor's IP and user agent, so locations and devices stay correct.

```bash
npm install @pieowl/bots
```

**Next.js** (or any framework with Fetch `Request` handlers):

```typescript title="app/api/pieowl/[...pieowl]/route.ts"
import { createRouteHandler } from '@pieowl/bots/route-handler';

export const { GET, POST } = createRouteHandler();
```

The same handler works in Hono (`app.all('/api/pieowl/*', (c) => handler(c.req.raw))`), Astro endpoints, SvelteKit `+server.ts` files, Nuxt server routes (`export default fromWebHandler(createRouteHandler())`) and Cloudflare Workers.

**Express**:

```typescript
import { createRouteHandler } from '@pieowl/bots/express';

app.use('/api/pieowl', createRouteHandler());
```

Then point the script at your route: set `apiUrl: '/api/pieowl'` and load `/api/pieowl/pieowl.js` (see [Frontend configuration](#frontend-configuration)). The proxy serves only `pieowl.js`. If you use [session replay](/docs/session-replay) with the proxy, set `sessionReplay.scriptUrl` to `https://pieowl.com/pieowl-replay.js`.

Proxying in any framework [#proxying-in-any-framework]

If your backend doesn't run JavaScript, build the same proxy yourself. Set up an endpoint on your domain (for example `api.domain.com` or `domain.com/api`) that forwards requests to Pieowl.

Below is the logic written out with a [Hono](https://hono.dev/) server. It follows the same steps as `@pieowl/bots`.

Hono example [#hono-example]

```typescript
import { Hono } from 'hono'

const app = new Hono()

// 1. Serve the tracking script (and the session replay script) from your domain
for (const file of ['pieowl.js', 'pieowl-replay.js']) {
  app.get(`/${file}`, async (c) => {
    try {
      const res = await fetch(`https://pieowl.com/${file}`)
      const text = await res.text()

      c.header('Content-Type', 'text/javascript')
      // Optional caching for 24 hours
      c.header('Cache-Control', 'public, max-age=86400, stale-while-revalidate=86400')
      return c.body(text)
    } catch (e) {
      return c.json({ error: 'Failed to fetch script' }, 500)
    }
  })
}

// 2. Forward tracked events
app.post('/track', async (c) => {
  const body = await c.req.json()
  
  // Forward the visitor's IP address (pick the right header for your hosting)
  const ip = c.req.header('cf-connecting-ip') ?? 
             c.req.header('x-forwarded-for')?.split(',')[0]

  const headers = new Headers()
  headers.set('Content-Type', 'application/json')
  headers.set('Origin', c.req.header('origin') ?? '')
  headers.set('User-Agent', c.req.header('user-agent') ?? '')
  headers.set('pieowl-client-id', c.req.header('pieowl-client-id') ?? '')
  
  if (ip) {
    headers.set('pieowl-client-ip', ip)
  }

  try {
    const res = await fetch('https://api.pieowl.com/track', {
      method: 'POST',
      headers,
      body: JSON.stringify(body),
    })
    return c.json(await res.text(), res.status)
  } catch (e) {
    return c.json(e, 500)
  }
})

// 3. Pass on what the script should collect (Settings → Site)
app.get('/config/tracking', async (c) => {
  const clientId = c.req.query('clientId') ?? ''
  const res = await fetch(
    `https://api.pieowl.com/config/tracking?clientId=${encodeURIComponent(clientId)}`
  )
  return c.json(await res.json(), res.status)
})

export default app
```

This sets up these endpoints:

1. `GET /pieowl.js` and `GET /pieowl-replay.js`: Fetch the Pieowl scripts and serve them from your domain. You only need the replay script if you use [session replay](/docs/session-replay).
2. `POST /track`: Receives events from the browser, adds the headers Pieowl needs (`User-Agent`, `Origin`, `Content-Type`, `pieowl-client-id` and `pieowl-client-ip`), and forwards them to the Pieowl API.
3. `GET /config/tracking`: Returns what the script collects by itself, as set in Settings → Site. Without it the script falls back to its defaults.

Frontend configuration [#frontend-configuration]

Once your proxy is running, point the Pieowl script at it instead of the default URLs.

```html
<script>
  window.pieowl=window.pieowl||function(){(window.pieowl.q=window.pieowl.q||[]).push(arguments)};
  window.pieowl('init', {
    apiUrl: 'https://api.domain.com',
    clientId: 'YOUR_CLIENT_ID',
  });
</script>
<script src="https://api.domain.com/pieowl.js" defer></script>
```

Now every request goes to your domain first, so ad blockers that look for third-party tracking domains let it through.
