A tracking pixel looks trivial until counting, durable history, caching, privacy, and partial failure arrive together.
The project uses a small request path to demonstrate clear service responsibilities: FastAPI handles the contract, Redis handles the hot counter, and PostgreSQL keeps the durable audit record.
Read the full project overview
An independent pixel tracking system for monitoring email engagement. It captures "email open" metrics by serving a 1x1 transparent image that triggers a backend event when loaded by a client.
The infrastructure uses Docker Compose to orchestrate three services: FastAPI for logic, Redis for high-performance counting, and PostgreSQL for persistent logging. Key features include isolated networks for security, persistent volumes for data integrity, and custom healthchecks to manage service startup order.
03 / Security
Threats, controls, and what remains
No control is presented as total risk elimination.
Privacy
Tracking URL exposes recipient identity
Control
Opaque token with no PII in the path
Residual risk
The token still acts as a correlatable identifier.
Data
Client IP becomes sensitive history
Control
Hash before storage and minimize request context
Residual risk
Hashes of low-entropy addresses can still be sensitive.
Integrity
Concurrent opens lose increments
Control
Atomic Redis pipeline
Residual risk
Counter and audit stores can temporarily diverge during failure.
04 / Operations
The unhappy path is part of the design
01
What if Redis is unavailable?
The atomic counter cannot be updated.
Signal
Internal connection and health checks fail.
Response
Return a bounded response policy and restore the counter service before claiming the event.
02
What if PostgreSQL is slow?
Durable auditing becomes the long pole in the request path.
Signal
Audit latency rises independently of the Redis increment.
Response
Preserve explicit failure semantics; do not silently present an incomplete audit as durable.
05 / Decisions
The trade-offs that shaped the build
Decision
Split counter and audit
Use each store for the behavior it serves best.
Reason
Fast atomic updates and durable history have different access patterns.
Trade-off
The service must make partial failure explicit.
Revisit when
When one datastore can satisfy both workloads without losing clarity.
Decision
Opaque token only
Keep identity details out of the URL.
Reason
URLs leak into logs, screenshots, and referrers.
Trade-off
Token lookup or mapping is required elsewhere.
Revisit when
Never for direct PII; only the token format may evolve.
Decision
Harden the tiny response
A one-pixel asset still deserves correct headers.
Reason
Caching and content sniffing can change observed behavior.
Trade-off
The response path carries a few more explicit rules.
Revisit when
When browser behavior or privacy policy changes.
06 / Implementation
How the decisions appear in the build
app/main.py
01# 1x1 pixel beacon. Atomic counting, isolated network, no PII in the URL.02from fastapi import FastAPI, Response, Request03import redis.asyncio as redis0405app = FastAPI()06r = redis.from_url("redis://redis:6379", decode_responses=True) # internal net only0708PIXEL = bytes.fromhex("47494638396101000100800000000000ffffff21f9040100"09 "0000002c00000000010001000002024401003b")1011@app.get("/o/{token}.gif")12async def open_pixel(token: str, request: Request) -> Response:13 async with r.pipeline(transaction=True) as pipe: # atomic multi-op14 await (pipe.hincrby(f"evt:{token}", "opens", 1)15 .hset(f"evt:{token}", "last_ip_hash", _hash(request.client.host))16 .execute())17 await audit.log(token=token, event="open") # durable in Postgres18 return Response(19 content=PIXEL, media_type="image/gif",20 headers={21 "Cache-Control": "no-store",22 "X-Content-Type-Options": "nosniff",23 "Content-Security-Policy": "default-src 'none'",24 },25 )
Representative / sanitized excerpt
Atomic Redis counting, hashed client IP, hardened response headers, no PII in the URL.
PythonFastAPIuvicornHTMLPostgreSQLRedis
07 / Evidence
Proof, source, and inspectable outcomes
08 / Results
What the project demonstrates
Fast counting and durable auditing have explicit responsibilities
The public URL contains no direct recipient PII
Container health and network boundaries are part of the application design
What worked
The small system makes datastore trade-offs easy to inspect.
Privacy choices are visible in the request contract.