# Server-side ingest code examples

> Server-side ingest examples that send an event with curl, Node.js, Python, PHP, Go, Rails and Next.js, forwarding the visitor's User-Agent and IP.

All examples send one `Signup` event for the visitor who made the current
request. Keep the ingest key in `PRIVATUS_INGEST_KEY`.

## curl

```sh
curl -X POST https://privatusanalytics.com/api/events \
  -H "Authorization: Bearer $PRIVATUS_INGEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [{
      "type": "event",
      "name": "Signup",
      "url": "https://example.com/signup",
      "props": { "plan": "pro" },
      "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0 Safari/537.36",
      "ip": "203.0.113.7"
    }]
  }'
```

The `user_agent` must be a real browser's: curl's own User-Agent is only on
the request, not in the event, so it doesn't matter here.

## Node.js (Express)

```js
app.post('/signup', async (req, res) => {
  // … create the account …
  const response = await fetch('https://privatusanalytics.com/api/events', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.PRIVATUS_INGEST_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      events: [{
        type: 'event',
        name: 'Signup',
        url: `https://example.com${req.originalUrl}`,
        referrer: req.get('referer'),
        props: { plan: req.body.plan },
        user_agent: req.get('user-agent'),
        ip: req.ip, // set app.set('trust proxy', …) behind a load balancer
      }],
    }),
  })
  const { data } = await response.json() // [{ index, status, reason }]
  res.redirect('/welcome')
})
```

## Python (Django or Flask)

```python
import os
import requests

def track_signup(request, plan):
    requests.post(
        "https://privatusanalytics.com/api/events",
        headers={"Authorization": f"Bearer {os.environ['PRIVATUS_INGEST_KEY']}"},
        json={"events": [{
            "type": "event",
            "name": "Signup",
            "url": request.build_absolute_uri(),  # Flask: request.url
            "props": {"plan": plan},
            "user_agent": request.headers.get("User-Agent"),
            "ip": request.META.get("REMOTE_ADDR"),  # Flask: request.remote_addr
        }]},
        timeout=5,
    )
```

## PHP

```php
<?php
$payload = ['events' => [[
    'type' => 'event',
    'name' => 'Signup',
    'url' => 'https://example.com' . $_SERVER['REQUEST_URI'],
    'props' => ['plan' => 'pro'],
    'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? null,
    'ip' => $_SERVER['REMOTE_ADDR'] ?? null,
]]];

$ch = curl_init('https://privatusanalytics.com/api/events');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('PRIVATUS_INGEST_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode($payload),
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 5,
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
```

## Go

```go
func trackSignup(r *http.Request, plan string) error {
	body, _ := json.Marshal(map[string]any{
		"events": []map[string]any{{
			"type":       "event",
			"name":       "Signup",
			"url":        "https://example.com" + r.URL.RequestURI(),
			"props":      map[string]any{"plan": plan},
			"user_agent": r.UserAgent(),
			"ip":         clientIP(r), // your helper: RemoteAddr or X-Forwarded-For from a trusted proxy
		}},
	})
	req, _ := http.NewRequestWithContext(r.Context(), http.MethodPost,
		"https://privatusanalytics.com/api/events", bytes.NewReader(body))
	req.Header.Set("Authorization", "Bearer "+os.Getenv("PRIVATUS_INGEST_KEY"))
	req.Header.Set("Content-Type", "application/json")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	return nil
}
```

## Ruby (Rails)

```ruby
require "net/http"

class PrivatusEvents
  URL = URI("https://privatusanalytics.com/api/events")

  def self.track(request, name, props = {})
    Net::HTTP.post(
      URL,
      { events: [{ type: "event", name:, url: request.original_url, props:,
                   user_agent: request.user_agent, ip: request.remote_ip }] }.to_json,
      "Authorization" => "Bearer #{ENV.fetch('PRIVATUS_INGEST_KEY')}",
      "Content-Type" => "application/json"
    )
  end
end

# In a controller:
PrivatusEvents.track(request, "Signup", plan: "pro")
```

Consider sending from a background job so a slow network never delays your
response, but **don't put the IP or User-Agent in the job payload** if your
job store is persistent. Send in the request, or drop `ip`.

## Next.js middleware

The [`@privatus/next`](/docs/install/nextjs#server-side-events) package's
`trackPageview()` and `trackEvent()` read the IP and User-Agent from the
incoming request for you and run on the Edge runtime.

> **Warning:** `@privatus/next` is not published on npm yet. Until it is,
> don't install a package with this name from the public registry,
> because anyone could have published it. Call the ingest API
> directly, as in the examples above, instead.
