Python
Server-side conversion tracking for Django, Flask, FastAPI or a worker.
Send conversions from your own back end. A browser event can be blocked and the customer may never load the confirmation page - the order row in your database always exists, so sending from there is what makes a conversion reliable.
Install
pip install pixelfox-sdkNo dependencies: a tracking SDK should not force a version of requests onto
your project. Python 3.8 or newer.
Create a client
import os
from pixelfox import PixelFox
pixelfox = PixelFox(api_key=os.environ["PIXELFOX_API_KEY"])| Argument | Default | Purpose |
|---|---|---|
api_key | required | Your site's key from the dashboard |
host | https://api.pixelfox.app | Where events are sent. Set it to your custom ingest endpoint, e.g. https://t.yourstore.com |
timeout | 3.0 | Seconds to wait before giving up on a request |
batch | False | Buffer events and send them in one request on flush() or on leaving a with block |
on_error | None | A callable given the error message whenever a send fails |
origin | None | Your site's origin, e.g. https://shop.example. Needed only when the site restricts allowed origins in Settings |
Send a purchase
pixelfox.purchase(
order_id="1042",
value=1200,
currency="BDT",
# From the `pixelfox_did` cookie, so this joins the same journey as the page
# views that led to it. Without it the sale looks like a new stranger.
distinct_id=request.COOKIES.get("pixelfox_did"),
email=order.email,
phone=order.phone,
items=[{"product_id": "p1", "name": "Merino Crew", "quantity": 2, "price": 600}],
customer={"first_name": "Asha", "city": "Dhaka", "country": "BD"},
client_ip=request.META.get("REMOTE_ADDR"),
client_user_agent=request.META.get("HTTP_USER_AGENT"),
)email and phone are what raise match quality on Meta and TikTok. They are
hashed server-side before reaching any ad platform and never reach a browser.
customer carries the remaining match keys: first_name, last_name, city,
state, zip, country and external_id (your own customer id). client_ip and
client_user_agent are the shopper's, from the checkout request, not your
server's.
If the browser pixel already fired this purchase, pass its event id as uuid_ so
the two are counted once.
Identify a visitor
Their earlier anonymous events are re-attributed to them server-side, so calling this after a signup backfills the whole session.
pixelfox.identify(distinct_id=did, email=user.email, phone=user.phone)Events that did not happen in a browser
POS sales, CRM updates and call-centre conversions have no cookie to join. email
and phone are the whole match here.
pixelfox.offline(
"purchase",
value=2500,
currency="BDT",
order_id="POS-7781",
phone="+8801712345678",
action_source="physical_store",
)action_source is passed through to the ad platforms; see
offline and CRM events for the accepted values.
Batching
For a worker sending many events, buffer and flush once:
with PixelFox(api_key=KEY, batch=True) as pixelfox:
for order in backfill:
pixelfox.purchase(order_id=order.id, value=order.total, currency="BDT")
# flushed on exitBatches larger than 50 are split automatically - the ingest endpoint rejects
anything bigger. Without batch=True every call sends immediately.
Errors
Nothing raises into your request path. Analytics failing must not fail a checkout.
pixelfox = PixelFox(
api_key=KEY,
on_error=lambda msg: logger.warning("pixelfox: %s", msg),
)
result = pixelfox.track("lead_submitted", distinct_id=did)
if not result.ok:
logger.warning(result.error)Every method returns a SendResult with ok, accepted (how many events the
server took) and error.
Reference
| Method | Purpose |
|---|---|
track(event, distinct_id=None, properties=None, uuid_=None) | Any event |
identify(distinct_id, email=None, phone=None, properties=None) | Attach an identity |
purchase(order_id, value, currency="BDT", distinct_id, email, phone, items, uuid_, properties, customer, client_ip, client_user_agent) | A conversion |
offline(event, value, currency="BDT", order_id, email, phone, distinct_id, action_source="physical_store", properties, uuid_) | A conversion that happened outside a browser |
flush() | Send buffered events |
send(events) | Send a list of PixelFoxEvent objects you built yourself |
Signals and SignalsEvent still work as aliases of PixelFox and PixelFoxEvent
for code written against the package's earlier name.
Python is online mode only. Offline mode needs somewhere on your own infrastructure to store analytics, which the WordPress plugin has and an SDK does not.