pieowl

How to add analytics to Python with the HTTP API

Track events from your Python app with the Pieowl HTTP API. No SDK needed: one POST request with your client ID and secret.

Pieowl TeamBeginner · 7 min · 8 Oct 2026
Guide · Python · HTTP API

This guide shows you how to send analytics events from any Python app to Pieowl. You'll write a small helper, track custom events and identify users.

Pieowl has no Python SDK. You don't need one. Tracking is one HTTP request to the Pieowl API, so a few lines of Python do the job. This works with Django, Flask, FastAPI, Celery and plain scripts.

Server-side tracking also means you decide exactly what you send, and ad blockers can't stop it.

Prerequisites

Install an HTTP client

This guide uses the popular requests library. Any HTTP client works, including httpx or the standard library's urllib.

pip install requests

Write a small helper

Every call goes to https://api.pieowl.com/track as a POST with a JSON body. Two headers prove the request is yours:

  • pieowl-client-id: your Client ID
  • pieowl-client-secret: your Client Secret

The body always has a type and a payload. For example, a track event looks like this:

{
  "type": "track",
  "payload": {
    "name": "user_signed_up",
    "profileId": "user_123",
    "properties": { "source": "website" }
  }
}

Put the request in one module so the rest of your app can import it.

# lib/pieowl.py
import os
import requests

API_URL = os.getenv("PIEOWL_API_URL", "https://api.pieowl.com")

HEADERS = {
    "Content-Type": "application/json",
    "pieowl-client-id": os.environ["PIEOWL_CLIENT_ID"],
    "pieowl-client-secret": os.environ["PIEOWL_CLIENT_SECRET"],
}

# Added to every event
GLOBAL_PROPERTIES = {
    "app_version": "1.0.0",
    "environment": os.getenv("ENVIRONMENT", "production"),
}


def send(type_, payload, client_ip=None, user_agent=None):
    headers = dict(HEADERS)
    if client_ip:
        headers["pieowl-client-ip"] = client_ip  # the visitor's IP, for the country lookup
    if user_agent:
        headers["User-Agent"] = user_agent  # the visitor's browser, for device data
    response = requests.post(
        f"{API_URL}/track",
        json={"type": type_, "payload": payload},
        headers=headers,
        timeout=5,
    )
    response.raise_for_status()
    return response.json()


def track(name, properties=None, profile_id=None, **request_info):
    payload = {"name": name, "properties": {**GLOBAL_PROPERTIES, **(properties or {})}}
    if profile_id:
        payload["profileId"] = str(profile_id)
    return send("track", payload, **request_info)


def identify(profile_id, first_name=None, last_name=None, email=None, properties=None):
    payload = {"profileId": str(profile_id), "properties": properties or {}}
    if first_name:
        payload["firstName"] = first_name
    if last_name:
        payload["lastName"] = last_name
    if email:
        payload["email"] = email
    return send("identify", payload)


def increment(profile_id, prop, value=1):
    return send("increment", {"profileId": str(profile_id), "property": prop, "value": value})

Set your credentials as environment variables:

# .env
PIEOWL_CLIENT_ID=your-client-id
PIEOWL_CLIENT_SECRET=your-client-secret

Track events

Call track with an event name and an optional dict of properties.

from lib.pieowl import track

# A simple event
track("button_clicked")

# An event with properties
track("purchase_completed", {
    "product_id": "123",
    "price": 99.99,
    "currency": "USD",
})

In a request handler, you usually take data from the request and track it next to your business logic. Here is a Django view. Passing the visitor's IP and user agent keeps the country and device data right, because the request to Pieowl comes from your server. Pieowl uses the IP for the country lookup and does not store it.

from django.http import JsonResponse
from lib.pieowl import track

def signup_view(request):
    if request.method == "POST":
        user = create_user(request.POST.get("email"), request.POST.get("name"))

        track(
            "user_signed_up",
            {"source": "website"},
            profile_id=user.id,
            client_ip=request.META.get("REMOTE_ADDR"),
            user_agent=request.META.get("HTTP_USER_AGENT"),
        )

        return JsonResponse({"success": True})

The same pattern works in Flask and FastAPI. Import the helper and call track wherever you want to record an event.

You can also track events from background tasks, such as async jobs, emails and scheduled work.

from celery import shared_task
from lib.pieowl import track

@shared_task
def send_email_task(user_id, email_type):
    try:
        send_email(user_id, email_type)
        track("email_sent", {"email_type": email_type}, profile_id=user_id)
    except Exception as e:
        track("email_failed", {"email_type": email_type, "error": str(e)}, profile_id=user_id)

requests waits for the reply. If you don't want a request to wait on analytics, call track from a background task or thread.

Identify users

identify saves a user's name, email and custom properties to their profile. Call it after login or signup.

from django.http import JsonResponse
from lib.pieowl import identify, track

def login_view(request):
    user = authenticate_user(request)

    identify(
        user.id,
        first_name=user.first_name,
        last_name=user.last_name,
        email=user.email,
        properties={"tier": user.plan},
    )

    track("user_logged_in", {"method": "email"}, profile_id=user.id)

    return JsonResponse({"success": True})

The HTTP API doesn't remember who you identified. Pass profile_id with every event you want linked to a user.

To keep a running count on a profile, such as logins or purchases, use increment. The profile must already exist, for example from an earlier identify call.

from lib.pieowl import increment

increment("user_456", "login_count")

Verify your setup

Run your app and trigger a few events. Open the Pieowl dashboard and go to the realtime view. Your events should show up within seconds.

No events? raise_for_status() turns errors into exceptions, so check your logs:

  • 401: the client ID or secret is wrong, or the secret is missing. Server-side calls need the secret.
  • 400: the body is wrong. The message says which field, for example a missing event name.

The Track API reference lists every event type and field.

Next steps

To learn how Pieowl handles privacy without cookies, read about cookieless analytics. If your Python app also has a web frontend, add the script tag for page views and clicks.

Is there a Python SDK?

No. Pieowl doesn't publish a Python package. Tracking is a single HTTP request, so the small helper in this guide is all you need. You own that code and can change it as you like.

Why do I need a client secret for server-side tracking?

A browser sends an origin that Pieowl checks against your site settings. A server does not. The client secret proves the events come from you and blocks anyone else from sending events to your site.

Does this work with async Python?

Yes. Use an async client such as httpx.AsyncClient and send the same JSON body and headers. Or run the requests helper in a background task so it doesn't block your handler.

Does Pieowl help with GDPR?

Pieowl is built for GDPR: no cookies, no stored IPs. With server-side tracking, you also decide exactly which data you send. Ask your legal advisor about your own setup.

Your first dashboard in five minutes.

14-day free trial, no card needed. Cloud in the EU. No cookies.