Logo
Apdf tutorials October 2026 4 min read

How to Add Per-Recipient Watermarks, Then Track Every Read

Confidential documents leak two ways: forwarded quietly, or screenshotted loudly. Watermarks handle the second — a name in the footer makes every screenshot traceable. But a watermark can't tell you the document is circulating before the leak, and tracking alone can't deter what it only observes.

So do both, in one pipeline: every recipient gets a copy stamped with their own name, behind their own tracked link. Deterrence on the page, visibility on the wire.

What you'll build
One script, one CSV, and each name comes back as a personal, watermarked, tracked copy: Miriam Wolfe → her copy says “licensed to Miriam Wolfe” — and reports every read she makes
Everything in this tutorial works on the free plan
1

Understand the four-call chain

The whole pipeline is API results feeding API inputs — no downloads in between:

POST /api/pdf/file/create      HTML in            → personal stamp page (async job)
POST /api/pdf/page/overlay     base + stamp in    → watermarked copy URL
POST /api/docs                 that URL in        → tracked document
POST /api/docs/{id}/links      name + email in    → the URL you send

The elegance is in step three: processing results are hosted URLs, and the documents endpoint ingests by URL — so the watermarked copy flows straight into tracking without ever touching your disk.

2

Run the pipeline over your list

#!/usr/bin/env bash
# Per-recipient watermark + tracked link, one pipeline per name.
API="https://apdf.io/api"
H=(-H "Authorization: Bearer $API_TOKEN" -H "Accept: application/json")

while IFS=, read -r NAME EMAIL; do
  # 1. generate the personal stamp page (async job)
  STAMP="<html><body style=\"margin:0;width:100%;height:100vh;position:relative;overflow:hidden;\">
    <div style=\"position:absolute;top:50%;left:50%;transform:translate(-50%,-50%) rotate(-35deg);font-family:Arial;font-size:64px;font-weight:bold;color:rgba(200,30,30,0.18);white-space:nowrap;letter-spacing:6px;\">CONFIDENTIAL</div>
    <div style=\"position:absolute;bottom:24px;left:0;right:0;text-align:center;font-family:Arial;font-size:11px;color:rgba(120,120,120,0.55);\">Copy licensed to $NAME · not for distribution</div>
  </body></html>"
  JOB=$(curl -s "${H[@]}" -X POST "$API/pdf/file/create" \
    --data-urlencode "html=$STAMP" -d "format=a4" \
    -d "margin_top=0" -d "margin_bottom=0" -d "margin_left=0" -d "margin_right=0" | jq -r .job_id)
  sleep 1
  until STAMP=$(curl -s "${H[@]}" -X POST "$API/job/status/check" -d "id=$JOB" | jq -re '.result.file') 2>/dev/null; do sleep 2; done

  # 2. overlay it onto every page of the report
  sleep 1
  STAMPED=$(curl -s "${H[@]}" -X POST "$API/pdf/page/overlay" \
    --data-urlencode "file=$BASE_PDF" --data-urlencode "overlay=$STAMP" -d "repeat=1" | jq -r .file)

  # 3. upload the personal copy as a tracked document and mint the link
  sleep 1
  DOC=$(curl -s "${H[@]}" -X POST "$API/docs" \
    --data-urlencode "file=$STAMPED" --data-urlencode "name=Board Report — $NAME" \
    -d "is_public=0" | jq -r .data.doc_id)
  sleep 1
  URL=$(curl -s "${H[@]}" -X POST "$API/docs/$DOC/links" \
    --data-urlencode "name=$NAME" --data-urlencode "email=$EMAIL" | jq -r .data.url)

  echo "$NAME → $URL"
  sleep 1
done < <(tail -n +2 recipients.csv)
$ BASE_PDF=https://your-site.example/board-report.pdf API_TOKEN=... ./stamp-and-track.sh
Miriam Wolfe → https://docs.apdf.io/studio/e6a74-8bc24-77c31?v=JbWCV5aQ
Viktor Chen → https://docs.apdf.io/studio/a42a6-f7ca0-9bf31?v=EPNDFGmS

We pulled Miriam's finished copy back down and checked: every page carries “Copy licensed to Miriam Wolfe · not for distribution” under the diagonal stamp. Viktor's says Viktor.

Tip: Processing result URLs expire after 1 hour — which is exactly why the pipeline chains them into the documents endpoint immediately instead of parking files anywhere.
3

What each copy buys you

  • Deterrence — a screenshot or printout of any page names its owner. Forwarding stops being free.
  • Per-person analytics — each copy is its own tracked document, so “Board Report — Miriam”'s sessions are Miriam's reading: every open, page and dwell time, plus the full history when you need it.
  • Surgical shutdown — one person's access ends by deactivating their link or archiving their document; nobody else notices. The revocation tutorial has the mechanics.

Keep the free plan's 3-tracked-documents limit in mind: per-recipient copies consume a document each, so this pattern is for the small, sensitive circle — board packs, term sheets, due-diligence material — not the hundred-lead campaign (that's per-recipient links on one document).

Where to go from here

Each half of this crossover has its own deep-dive.

Ready to see who reads?