LinkedIn Lead Gen Form hidden fields: tag each lead with its variant

A LinkedIn Lead Gen Form allows up to 20 hidden fields. Keep your own index-to-variant table from the Sume bulk queue so every lead traces to one creative.

5 min readSume
All posts

LinkedIn's Lead Gen Form specifications list a Settings section where you can add up to 20 hidden fields. If you run many creative variants, plan one of them to carry a variant id so each lead can be traced back to the creative that produced it. This post covers only the Sume side of that: how to keep a reliable index, variant id and run id table from a bulk queue. What a hidden field holds and how LinkedIn fills it is on LinkedIn's page, which I did not find a value source on, so read it before you build.

The reason to do the mapping yourself: Sume's bulk-run docs say the input object is caller data the Format reads, and that your own reference data in it does not come back in output. The queue does give you a stable index for each item and a run_id once the item starts.

What the queue gives you to join on

Each item in the queue receipt has an index (the zero-based position you submitted) and a run_id after dispatch, so a join key exists without Sume echoing anything back.

Queue item fields from Sume's bulk-run docs and the hidden-field limit from LinkedIn's Lead Gen Form specifications (read 2026-10-05)
FieldSourceUse
Item indexSume queue receiptZero-based position in the submitted items array
Item run_idSume queue receiptnull while queued; read the child at GET /v1/format-runs/{run_id}
Hidden fieldsLinkedIn Lead Gen FormUp to 20 additional fields

Write the mapping before you submit

The script below fixes the variant ids first, submits the queue, and saves a CSV that pairs each index with its variant id and run id. Replace acme/offer-ads with a Format you own.

import csv, os, uuid, requests

API = "https://api.sume.com"
H = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
variants = ["hook-a", "hook-b", "hook-c"]
items = [{"instruction": f"Offer image, hook {v}", "input": {"variant_id": v}}
         for v in variants]
r = requests.post(f"{API}/v1/formats/acme/offer-ads/bulk-runs",
                  headers={**H, "Idempotency-Key": str(uuid.uuid4())},
                  json={"concurrency": 3, "items": items}, timeout=30)
r.raise_for_status()
q = r.json()["data"]
with open("variant-map.csv", "w", newline="") as f:
    w = csv.writer(f)
    w.writerow(["queue_id", "index", "variant_id", "run_id"])
    for it in q["items"]:
        w.writerow([q["id"], it["index"], variants[it["index"]], it["run_id"]])

Keep the table current

A run_id can be null for queued items on the first receipt. Poll the queue's status_url and rewrite the CSV once the items have started, or join on index alone.

  • Store the queue id with every row; the API has no list-queues endpoint.
  • Never reuse a variant id for a different creative inside one campaign.
  • If you retry an item, record the new run id next to the same variant id.

Sources

Related posts

More in Use cases

All Use cases posts

Written by Sume