Power Your Attribution with Server-to-Server Postback Tracking β‘
A lightweight affiliate postback tracking system π built with Node.js, Postgres, and Next.js. It lets affiliates track clicks, record conversions via server-to-server postbacks, and monitor results in a sleek dashboard. Designed as an MVP, it highlights the core principles of affiliate tracking and attributionβsimple, clear, and extendable. Perfect for learning or building upon in real-world projects. π
Server-to-Server (S2S) tracking is a method where conversion events are transmitted directly between servers, instead of relying on browser scripts or cookies. This approach delivers higher accuracy, stronger security, and immunity to ad blockers, making it the gold standard in modern affiliate marketing. By cutting out client-side dependencies, S2S ensures that every click and conversion is logged reliably, even in environments where cookies are restricted.
This project is a minimal viable product (MVP) of an affiliate tracking engine, built for clarity and extendability.
It demonstrates the core building blocks of affiliate attribution:
- Click Storage: Log and map affiliate clicks with campaigns.
- Postback Handling: Receive advertiser postbacks securely.
- Click-to-Conversion Match: Attribute conversions to the right clicks.
- Dashboard Insights: Visualize clicks and conversions in real time.
- Lightweight & Extendable: Designed as a foundation to build upon.
- π― Click Tracking: Map affiliates and campaigns seamlessly for accurate attribution.
- π Secure Postbacks: Record conversions safely through server-to-server endpoints.
- π οΈ Unique URLs: Auto-generate affiliate-specific postback links with ease.
- π Modern Dashboard: View clicks and conversions in a clean, intuitive interface.
- π‘οΈ Fraud Prevention: Validate clicks before logging conversions to ensure trust.
- ποΈ Postgres-Powered: Scalable storage backed by PostgreSQL for reliability.
Important
Use the Docker image or run locally via localhost to get started now.
You can visit the live site here : --Temporarily Not Deployed--
- Node.js (Express) β Backend API for clicks and postbacks
- PostgreSQL β Relational database for affiliates, clicks, conversions
- Next.js (React) β Frontend affiliate dashboard with SSR
- Tailwind CSS β Modern utility-first styling for responsive UI
- REST API β Communication between frontend, backend, and database
- Git & GitHub β Version control and collaborative development
- Docker β A container platform for easy deployment, scalability, and app management.
- Node.js v22.14.0 or higher
- pnpm or npm (package managers)
- Code Editor (e.g., VS Code)
- Git (version control system)
- Docker (for containerized deployments)
- PostgreSQL (relational database)
- Modern Browser (latest Chrome, Firefox, or Edge for development/testing)
- First Read this License & their terms then proceed.
- Star β the Repository
- Fork the repository (Optional)
- Project Setup:
- Clone the repository:
git clone https://github.com/UjjwalSaini07/Affiliate-Postback-Engine.git
- Navigate to the project main directory:
cd Affiliate-Postback-Engine
Important
All these cd directory paths are relative to the root directory of the cloned project.
- Navigate to the project Frontend directory:
cd frontend
- Install Frontend dependencies:
pnpm install
- Navigate to the project Backend directory:
cd backend
- Install Backend dependencies:
pnpm install
cd Affiliate-Postback-Engine
- Start PostgreSQL from Docker: Before that Install Locally
docker compose up -d
docker compose ps

- It Open the Database on Port - 5432
- Start the Frontend Development server
cd frontend
pnpm dev
- Frontend Operates on
Port: http://localhost:3000
- Start the Backend Development server
cd backend
pnpm dev
- Backend Operates on
Port: http://localhost:4000
- You can run it using Docker or initialize it locally with the PostgreSQL command-line service β it depends on how you prefer to start the database engine.
- Database Operates on
Port: http://localhost:5433
- Start the Docker Engine Locally or Use Any Service Globally
- Navigate to the project Root directory:
cd Affiliate-Postback-Engine
- Run DockerFile:
docker-compose up --build
- Wait for Generating the Image


- Now Simply use the Project using Docker Container
- If u Want Direct Image Without Cloning So Contact with Me. Contact
- This project provides lightweight yet powerful tracking and postback APIs designed for affiliate marketing workflows.
- Current MVP implementation uses
GET
requests for simplicity (future versions will supportPOST
with JSON payloads for better scalability). - Each endpoint is designed with idempotency in mind, ensuring duplicate clicks or conversions are safely ignored.
- Responses are JSON formatted, making them easy to consume programmatically or test manually.
- Built for real-world extensibility: future improvements will include authentication, HMAC signing for postbacks, and rate limiting for better security and reliability.
- Can be easily tested using
curl
, Postman, or Hoppscotch without any extra setup.
-
Log a Click:
GET /click?affiliate_id=&campaign_id=&click_id=
-
Send a Postback (Conversion):
GET /postback?affiliate_id=&click_id=&amount=¤cy=
-
List Affiliates:
GET /affiliates
-
Get All Clicks for an Affiliate:
GET /affiliates/:id/clicks
-
Get All Conversions for an Affiliate:
GET /affiliates/:id/conversions
- π Log a click
curl "http://localhost:4000/click?affiliate_id=1&campaign_id=1&click_id=abc123"
- π Send a postback (conversion)
curl "http://localhost:4000/postback?affiliate_id=1&click_id=abc123&amount=100¤cy=USD"
- π Check for Error- Something Went Wrong {Passes Wrong Payload}
curl "http://localhost:4000/postback?affiliate_id=2&click_id=abc123&amount=100¤cy=USD"
- π Get conversions for affiliate 1
curl "http://localhost:4000/affiliates/1/conversions"




- Open Powershell or Cmd on dir -
cd Affiliate-Postback-Engine
- Run this to view all conversions joined with their clicks (ordered by affiliate):
psql -U postgres -h localhost -p 5433 -d affiliate_dev -c "
SELECT c.id, c.amount, c.currency, cl.click_id, cl.affiliate_id
FROM conversions c
JOIN clicks cl ON c.click_id = cl.id
ORDER BY cl.affiliate_id;"
- π Individual Check
psql -U postgres -h localhost -p 5433 -d affiliate_dev -c "
SELECT * FROM clicks WHERE affiliate_id = 3 AND click_id = 'abc999';"
- If 0 rows returned, insert the click first:
psql -U postgres -h localhost -p 5433 -d affiliate_dev -c "
INSERT INTO clicks (affiliate_id, campaign_id, click_id)
VALUES (3, 2, 'abc999')
ON CONFLICT (affiliate_id, campaign_id, click_id) DO NOTHING;"
- Adjust campaign_id to a valid campaign for that affiliate.
- Insert conversion safely
psql -U postgres -h localhost -p 5433 -d affiliate_dev -c "
INSERT INTO conversions (click_id, amount, currency)
VALUES ((SELECT id FROM clicks WHERE affiliate_id = 3 AND click_id = 'abc999'), 200, 'USD')
ON CONFLICT (click_id) DO NOTHING;"
- Important Alter Table Commands
psql -U postgres -h localhost -p 5433 -d affiliate_dev -c "
INSERT INTO clicks (click_id, affiliate_id, campaign_id)
VALUES ('usgs07', 1, 2)
ON CONFLICT (click_id) DO NOTHING;"
psql -U postgres -h localhost -p 5433 -d affiliate_dev -c "
INSERT INTO conversions (click_id, amount, currency)
VALUES (
(SELECT id FROM clicks WHERE click_id = 'valid123' LIMIT 1), 550, 'USD')
ON CONFLICT (click_id) DO NOTHING;"




psql -U postgres -h localhost -p 5433 -d affiliate_dev -c "
INSERT INTO clicks (affiliate_id, campaign_id, click_id)
VALUES
(1, 1, 'abc123'),
(1, 1, 'def456')
ON CONFLICT (affiliate_id, campaign_id, click_id) DO NOTHING;"
psql -U postgres -h localhost -p 5433 -d affiliate_dev -c "
INSERT INTO conversions (click_id, amount, currency)
VALUES
((SELECT id FROM clicks WHERE affiliate_id = 1 AND click_id = 'abc123'), 100, 'USD'),
((SELECT id FROM clicks WHERE affiliate_id = 1 AND click_id = 'def456'), 150, 'USD')
ON CONFLICT (click_id) DO NOTHING;"
psql -U postgres -h localhost -p 5433 -d affiliate_dev -c "
INSERT INTO clicks (affiliate_id, campaign_id, click_id)
VALUES
(2, 2, 'xyz999'),
(2, 2, 'uvw111')
ON CONFLICT (affiliate_id, campaign_id, click_id) DO NOTHING;"
psql -U postgres -h localhost -p 5433 -d affiliate_dev -c "
INSERT INTO conversions (click_id, amount, currency)
VALUES
((SELECT id FROM clicks WHERE affiliate_id = 2 AND click_id = 'xyz999'), 50, 'USD'),
((SELECT id FROM clicks WHERE affiliate_id = 2 AND click_id = 'uvw111'), 75, 'USD')
ON CONFLICT (click_id) DO NOTHING;"
psql -U postgres -h localhost -p 5433 -d affiliate_dev -c "
INSERT INTO clicks (affiliate_id, campaign_id, click_id)
VALUES
(3, 1, 'lmn123'),
(3, 1, 'opq456')
ON CONFLICT (affiliate_id, campaign_id, click_id) DO NOTHING;"
psql -U postgres -h localhost -p 5433 -d affiliate_dev -c "
INSERT INTO conversions (click_id, amount, currency)
VALUES
((SELECT id FROM clicks WHERE affiliate_id = 3 AND click_id = 'lmn123'), 120, 'USD'),
((SELECT id FROM clicks WHERE affiliate_id = 3 AND click_id = 'opq456'), 90, 'USD')
ON CONFLICT (click_id) DO NOTHING;"
- Validation: Every conversion request validates that the given
affiliate_id
andclick_id
pair exists before inserting. This ensures conversions cannot be logged against mismatched or invalid clicks. - Idempotency:
- The
conversions
table enforces aUNIQUE(click_id)
constraint to guarantee no duplicate conversions for the same click. - The
/postback
route also performs a check and returns409 Conflict
if a duplicate is attempted.
- The
- SQL Injection Prevention: All database interactions use parameterized queries (
$1, $2, β¦
) to safely handle user input. - Optional Security Improvements:
- HMAC-Signed Postbacks: Advertisers could sign each postback request using a shared secret.
- The backend would verify the signature before processing, ensuring requests cannot be forged or tampered with.
- Caveat (MVP Limitation):
- Current implementation uses
GET
requests for simplicity (common in affiliate postback flows). - Future iterations should move to
POST + JSON body + HMAC
for stronger security and industry alignment.
- Current implementation uses
- PostgreSQL as a Client
- Install Postgres locally:
- Download from:
https://www.postgresql.org/download/windows/
- During setup, tick βCommand Line Toolsβ.
- Open a new PowerShell or Git Bash and run:
psql -U postgres -h localhost -p 5432 -d affiliate_dev -f db/schema.sql
- Use Dockerβs built-in psql inside your container
- If youβre running Postgres in Docker (like we set up with docker-compose.yml)
docker exec -it affiliate-postback-engine-db-1 psql -U postgres -d affiliate_dev -f /docker-entrypoint-initdb.d/schema.sql
- But for that to work, youβd need to copy your
schema.sql
andseed.sql
into the container first
docker cp db/schema.sql affiliate-postback-engine-db-1:/docker-entrypoint-initdb.d/schema.sql
docker cp db/seed.sql affiliate-postback-engine-db-1:/docker-entrypoint-initdb.d/seed.sql
- Then run the
docker exec
command. - Test connection
psql -U postgres -h localhost -p 5433 -d affiliate_dev -c "\dt"

Important
If this is Not shown on Test Connection So Follow Below Procedure Step By Step, Author: UjjwalS
psql -U postgres -h localhost -p 5433 -c "CREATE DATABASE affiliate_dev;"
- Enter your password when prompted.
psql -U postgres -h localhost -p 5433 -d affiliate_dev -f db/schema.sql
psql -U postgres -h localhost -p 5433 -d affiliate_dev -f db/seed.sql
psql -U postgres -h localhost -p 5433 -d affiliate_dev -c "\dt"
- Your database setup is complete with seed data and schema synchronization.
- Load sample data
psql -U postgres -h localhost -p 5433 -d affiliate_dev -f db/seed.sql
- Then check
psql -U postgres -h localhost -p 5433 -d affiliate_dev -c "SELECT * FROM affiliates;"





Feel free to reach out if you have any questions or suggestions!
- Raise an issue for the same Issue
- Github: @Ujjwal Saini
License Credential LICENSE
Sorry But this repository not welcome Contributions! Yes u gave a Feedback and Suggestion via raising the Issue.