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
- A Python project
- A Pieowl account (start a 14-day free trial)
- Your Client ID and Client Secret from the dashboard
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 requestsWrite 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 IDpieowl-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-secretTrack 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.