Python Quickstart
Get up and running with Zenovay analytics in your Python application in under 5 minutes using the requests library to send events directly to the Zenovay tracking endpoint.
Installation
Install the requests library (if not already installed):
pip install requests
# or
poetry add requests
# or
pipenv install requests
Zenovay does not have an official Python SDK. Instead, you send events directly via HTTP to the tracking endpoint. This keeps your integration lightweight and dependency-free.
Basic Setup
1. Create a Zenovay Helper
Create a simple helper module for sending events:
# analytics.py
import os
import requests
import uuid
from datetime import datetime, timezone
ZENOVAY_TRACKING_CODE = os.getenv('ZENOVAY_TRACKING_CODE')
ZENOVAY_ENDPOINT = f'https://api.zenovay.com/e/{ZENOVAY_TRACKING_CODE}'
def track_event(event_name, url, visitor_id=None, session_id=None, properties=None):
"""Send a custom event to Zenovay."""
payload = {
'event_type': 'custom',
'event_name': event_name,
'url': url,
'visitor_id': visitor_id or str(uuid.uuid4()),
'session_id': session_id or str(uuid.uuid4()),
'properties': properties or {},
'timestamp': datetime.now(timezone.utc).isoformat(),
}
try:
response = requests.post(ZENOVAY_ENDPOINT, json=payload, timeout=5)
response.raise_for_status()
return response.json()
except requests.RequestException as e:
print(f'Zenovay tracking error: {e}')
return None
def identify_user(user_id, email, url, visitor_id=None, session_id=None, extra_traits=None):
"""Send an identify event to Zenovay."""
user_profile = {'user_id': str(user_id), 'email': email}
if extra_traits:
user_profile.update(extra_traits)
payload = {
'event_type': 'identify',
'event_name': 'user_identified',
'user_profile': user_profile,
'url': url,
'visitor_id': visitor_id or str(uuid.uuid4()),
'session_id': session_id or str(uuid.uuid4()),
'timestamp': datetime.now(timezone.utc).isoformat(),
}
try:
response = requests.post(ZENOVAY_ENDPOINT, json=payload, timeout=5)
response.raise_for_status()
return response.json()
except requests.RequestException as e:
print(f'Zenovay identify error: {e}')
return None
2. Add Client-Side Tracking
Add the Zenovay script to your HTML templates for automatic page view tracking:
<!-- templates/base.html (Jinja2) -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title }}</title>
<!-- Zenovay Analytics -->
<script src="https://api.zenovay.com/z.js"
data-tracking-code="YOUR_TRACKING_CODE"
async></script>
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
3. Track Server-Side Events
Track events from your Python code:
# app.py
from flask import Flask, request, jsonify
from analytics import track_event, identify_user
app = Flask(__name__)
@app.route('/signup', methods=['POST'])
def signup():
data = request.get_json()
email = data.get('email')
name = data.get('name')
plan = data.get('plan')
try:
# Create user account
user_id = create_user(email, name, plan)
# Track signup event
track_event(
event_name='signup_completed',
url='https://yoursite.com/signup',
properties={
'plan': plan,
'source': 'website',
'user_id': str(user_id),
}
)
return jsonify({'success': True, 'user_id': user_id})
except Exception as e:
return jsonify({'error': str(e)}), 500
Environment Configuration
Create a .env file:
# .env
ZENOVAY_TRACKING_CODE=your_tracking_code_here
Load environment variables using python-dotenv:
pip install python-dotenv
# app.py
import os
from dotenv import load_dotenv
load_dotenv()
# Now you can use os.getenv()
tracking_code = os.getenv('ZENOVAY_TRACKING_CODE')
Common Use Cases
Track User Identification
# auth.py
from flask import session, request, jsonify
from analytics import track_event, identify_user
@app.route('/login', methods=['POST'])
def login():
data = request.get_json()
email = data.get('email')
password = data.get('password')
try:
user = authenticate_user(email, password)
# Store user in session
session['user_id'] = user['id']
# Identify user in Zenovay
identify_user(
user_id=user['id'],
email=user['email'],
url='https://yoursite.com/login',
extra_traits={
'name': user['name'],
'plan': user.get('plan'),
}
)
# Track login event
track_event(
event_name='user_logged_in',
url='https://yoursite.com/login',
properties={
'method': 'password',
'user_id': str(user['id']),
}
)
return jsonify({'success': True, 'user': user})
except Exception as e:
return jsonify({'error': 'Invalid credentials'}), 401
Track E-commerce Events
# checkout.py
from flask import session, request, jsonify
from analytics import track_event
@app.route('/checkout', methods=['POST'])
def checkout():
user_id = session.get('user_id')
data = request.get_json()
cart_items = data.get('cart_items')
total = data.get('total')
try:
# Process order
order = create_order(user_id, cart_items, total)
# Track purchase
track_event(
event_name='purchase_completed',
url='https://yoursite.com/checkout',
properties={
'order_id': order['id'],
'revenue': total,
'currency': 'USD',
'user_id': str(user_id),
'items': [
{
'product_id': item['id'],
'quantity': item['quantity'],
'price': item['price']
}
for item in cart_items
]
}
)
return jsonify({'success': True, 'order': order})
except Exception as e:
return jsonify({'error': str(e)}), 500
Track API Usage
# api.py
import time
from flask import request, jsonify
from analytics import track_event
@app.route('/api/generate', methods=['POST'])
def generate():
data = request.get_json()
user_id = data.get('user_id')
model = data.get('model')
prompt = data.get('prompt')
try:
start_time = time.time()
result = generate_content(model, prompt)
response_time = (time.time() - start_time) * 1000 # ms
# Track API usage
track_event(
event_name='api_request',
url='https://yoursite.com/api/generate',
properties={
'endpoint': '/api/generate',
'model': model,
'success': True,
'response_time': response_time,
'user_id': str(user_id),
}
)
return jsonify(result)
except Exception as e:
# Track API error
track_event(
event_name='api_error',
url='https://yoursite.com/api/generate',
properties={
'endpoint': '/api/generate',
'error': str(e),
'user_id': str(user_id),
}
)
return jsonify({'error': str(e)}), 500
Middleware Pattern
Create reusable analytics middleware:
# middleware/analytics.py
from flask import session, request
from analytics import track_event, identify_user
class AnalyticsMiddleware:
def __init__(self, app):
self.app = app
@app.before_request
def identify_logged_in_user():
if 'user_id' in session:
user = get_user_by_id(session['user_id'])
if user:
identify_user(
user_id=user['id'],
email=user['email'],
url=request.url,
extra_traits={
'name': user['name'],
'plan': user.get('plan'),
}
)
@app.after_request
def track_response(response):
if request.endpoint and response.status_code < 400:
track_event(
event_name='page_viewed',
url=request.url,
properties={
'page': request.path,
'method': request.method,
'status_code': response.status_code,
}
)
return response
# Usage
from middleware.analytics import AnalyticsMiddleware
app = Flask(__name__)
AnalyticsMiddleware(app)
Error Tracking
Set up global error tracking:
# error_handler.py
import traceback
from flask import session, request, jsonify
from analytics import track_event
@app.errorhandler(Exception)
def handle_exception(e):
user_id = session.get('user_id')
# Track error
track_event(
event_name='server_error',
url=request.url,
properties={
'error_type': type(e).__name__,
'error_message': str(e),
'error_traceback': traceback.format_exc(),
'path': request.path,
'method': request.method,
'user_id': str(user_id) if user_id else None,
}
)
return jsonify({'error': 'Internal server error'}), 500
Django Integration
For Django applications:
# settings.py
ZENOVAY_TRACKING_CODE = os.getenv('ZENOVAY_TRACKING_CODE')
# analytics/client.py
import os
import requests
import uuid
from datetime import datetime, timezone
from django.conf import settings
ZENOVAY_ENDPOINT = f'https://api.zenovay.com/e/{settings.ZENOVAY_TRACKING_CODE}'
def track_event(event_name, url, properties=None):
payload = {
'event_type': 'custom',
'event_name': event_name,
'url': url,
'visitor_id': str(uuid.uuid4()),
'session_id': str(uuid.uuid4()),
'properties': properties or {},
'timestamp': datetime.now(timezone.utc).isoformat(),
}
try:
response = requests.post(ZENOVAY_ENDPOINT, json=payload, timeout=5)
response.raise_for_status()
except requests.RequestException as e:
print(f'Zenovay tracking error: {e}')
def identify_user(user_id, email, url, extra_traits=None):
user_profile = {'user_id': str(user_id), 'email': email}
if extra_traits:
user_profile.update(extra_traits)
payload = {
'event_type': 'identify',
'event_name': 'user_identified',
'user_profile': user_profile,
'url': url,
'visitor_id': str(uuid.uuid4()),
'session_id': str(uuid.uuid4()),
'timestamp': datetime.now(timezone.utc).isoformat(),
}
try:
response = requests.post(ZENOVAY_ENDPOINT, json=payload, timeout=5)
response.raise_for_status()
except requests.RequestException as e:
print(f'Zenovay identify error: {e}')
# analytics/middleware.py
from analytics.client import track_event, identify_user
class AnalyticsMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# Identify user
if request.user.is_authenticated:
identify_user(
user_id=str(request.user.id),
email=request.user.email,
url=request.build_absolute_uri(),
extra_traits={'username': request.user.username},
)
response = self.get_response(request)
# Track page view
if response.status_code < 400:
track_event(
event_name='page_viewed',
url=request.build_absolute_uri(),
properties={
'path': request.path,
'method': request.method,
'user_id': str(request.user.id) if request.user.is_authenticated else None,
}
)
return response
# settings.py
MIDDLEWARE = [
# ...
'analytics.middleware.AnalyticsMiddleware',
]
# views.py
from analytics.client import track_event
def signup_view(request):
if request.method == 'POST':
user = User.objects.create_user(
username=request.POST['username'],
email=request.POST['email'],
password=request.POST['password']
)
# Track signup
track_event(
event_name='user_signup',
url=request.build_absolute_uri(),
properties={
'user_id': str(user.id),
'email': user.email,
'source': 'web',
}
)
return redirect('dashboard')
return render(request, 'signup.html')
FastAPI Integration
For FastAPI applications:
# main.py
import os
import uuid
from datetime import datetime, timezone
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
import requests as http_requests
app = FastAPI()
ZENOVAY_TRACKING_CODE = os.getenv('ZENOVAY_TRACKING_CODE')
ZENOVAY_ENDPOINT = f'https://api.zenovay.com/e/{ZENOVAY_TRACKING_CODE}'
def track_event(event_name, url, properties=None):
payload = {
'event_type': 'custom',
'event_name': event_name,
'url': url,
'visitor_id': str(uuid.uuid4()),
'session_id': str(uuid.uuid4()),
'properties': properties or {},
'timestamp': datetime.now(timezone.utc).isoformat(),
}
try:
http_requests.post(ZENOVAY_ENDPOINT, json=payload, timeout=5)
except http_requests.RequestException:
pass
@app.middleware("http")
async def analytics_middleware(request: Request, call_next):
response = await call_next(request)
if response.status_code < 400:
track_event(
event_name='page_viewed',
url=str(request.url),
properties={
'path': request.url.path,
'method': request.method,
}
)
return response
@app.post("/signup")
async def signup(email: str, name: str, plan: str):
try:
user_id = create_user(email, name, plan)
track_event(
event_name='signup_completed',
url='https://yoursite.com/signup',
properties={
'plan': plan,
'user_id': str(user_id),
}
)
return {"success": True, "user_id": user_id}
except Exception as e:
return JSONResponse(
status_code=500,
content={"error": str(e)}
)
@app.exception_handler(Exception)
async def exception_handler(request: Request, exc: Exception):
track_event(
event_name='server_error',
url=str(request.url),
properties={
'error': str(exc),
'path': request.url.path,
}
)
return JSONResponse(
status_code=500,
content={"error": "Internal server error"}
)
Async Support
Use httpx for non-blocking async tracking:
# async_analytics.py
import os
import uuid
from datetime import datetime, timezone
import httpx
ZENOVAY_TRACKING_CODE = os.getenv('ZENOVAY_TRACKING_CODE')
ZENOVAY_ENDPOINT = f'https://api.zenovay.com/e/{ZENOVAY_TRACKING_CODE}'
async def track_event_async(event_name, url, properties=None):
payload = {
'event_type': 'custom',
'event_name': event_name,
'url': url,
'visitor_id': str(uuid.uuid4()),
'session_id': str(uuid.uuid4()),
'properties': properties or {},
'timestamp': datetime.now(timezone.utc).isoformat(),
}
async with httpx.AsyncClient() as client:
try:
await client.post(ZENOVAY_ENDPOINT, json=payload, timeout=5)
except httpx.RequestError as e:
print(f'Zenovay tracking error: {e}')
# Usage with FastAPI
@app.post("/signup")
async def signup(email: str, plan: str):
user_id = await create_user(email, plan)
await track_event_async(
event_name='signup_completed',
url='https://yoursite.com/signup',
properties={'plan': plan, 'user_id': str(user_id)}
)
return {"success": True}
Background Tasks
Track events in background tasks using Celery:
# tasks.py
import os
import uuid
from datetime import datetime, timezone
import requests
from celery import Celery
celery = Celery('tasks', broker='redis://localhost:6379')
ZENOVAY_TRACKING_CODE = os.getenv('ZENOVAY_TRACKING_CODE')
ZENOVAY_ENDPOINT = f'https://api.zenovay.com/e/{ZENOVAY_TRACKING_CODE}'
@celery.task
def track_event_bg(event_name, url, properties=None):
payload = {
'event_type': 'custom',
'event_name': event_name,
'url': url,
'visitor_id': str(uuid.uuid4()),
'session_id': str(uuid.uuid4()),
'properties': properties or {},
'timestamp': datetime.now(timezone.utc).isoformat(),
}
try:
requests.post(ZENOVAY_ENDPOINT, json=payload, timeout=5)
except requests.RequestException:
pass
# Usage
from tasks import track_event_bg
@app.route('/signup', methods=['POST'])
def signup():
user_id = create_user(request.json)
# Track in background
track_event_bg.delay(
event_name='signup_completed',
url='https://yoursite.com/signup',
properties={'plan': request.json['plan'], 'user_id': str(user_id)}
)
return jsonify({'success': True})
Testing
Mock the tracking calls in your tests:
# tests/test_signup.py
import pytest
from unittest.mock import patch
from app import app
@pytest.fixture
def client():
app.config['TESTING'] = True
with app.test_client() as client:
yield client
@patch('analytics.requests.post')
def test_signup_tracks_event(mock_post, client):
mock_post.return_value.status_code = 200
mock_post.return_value.raise_for_status = lambda: None
response = client.post('/signup', json={
'email': '[email protected]',
'name': 'Test User',
'plan': 'pro'
})
assert response.status_code == 200
mock_post.assert_called()
call_args = mock_post.call_args
payload = call_args[1]['json']
assert payload['event_name'] == 'signup_completed'
assert payload['properties']['plan'] == 'pro'
Tracking Endpoint Reference
All server-side events are sent as POST requests to:
https://api.zenovay.com/e/YOUR_TRACKING_CODE
Custom Event Payload
{
"event_type": "custom",
"event_name": "event_name_here",
"url": "https://yoursite.com/page",
"visitor_id": "unique-visitor-id",
"session_id": "unique-session-id",
"properties": { "key": "value" },
"timestamp": "2026-02-27T12:00:00.000Z"
}
Identify Event Payload
{
"event_type": "identify",
"event_name": "user_identified",
"user_profile": { "user_id": "123", "email": "[email protected]" },
"url": "https://yoursite.com",
"visitor_id": "unique-visitor-id",
"session_id": "unique-session-id",
"timestamp": "2026-02-27T12:00:00.000Z"
}
Next Steps
- API Reference - Full API documentation
- Custom Events - Learn about event tracking
- Privacy Compliance - GDPR and CCPA setup
- Dashboard Overview - Understand your data
Getting Help
- Documentation: docs.zenovay.com
- Support: [email protected]