In the 2025 Insights Association and GDQ benchmark, 75.2% of supplier records used encrypted or server-to-server links. Research agencies were at 91.5%. Put the other way round, roughly one supplier record in four arrived on a link that nothing stopped a respondent from editing.

A survey complete link is worth money. If a respondent can see it, they can bookmark it, share it, or change terminate to complete and press enter. Signatures are the cheapest fix available.

https://researchdart.com/s/end/complete?rdid=01k8zq4r2mxv6c3e9ab7t5wq1n

Everything needed to record a complete is visible. Checking that the session ID exists stops made-up IDs. First-outcome-wins stops a session that already ended from being changed. Neither stops a respondent who screened out on the first question from editing their own still-open session into a complete.

What the signature adds

HMAC combines a message with a secret key into a short fingerprint. Anyone holding the key can produce the same fingerprint from the same message. Nobody else can, and changing one character of the message changes the whole fingerprint.

For redirects, the message is the URL and the key is shared between the survey owner and the router. The survey appends the fingerprint. The router recomputes it and refuses the redirect if they differ.

The ResearchDart format

The rules are the same for supplier entry links and buyer endlinks.

  1. Build the URL with every parameter except the signature.
  2. Take the path and query: everything from the first / after the domain.
  3. Compute HMAC-SHA256 of that string with your secret, as lowercase hex.
  4. Append it as the last parameter, h.

The domain and scheme are left out on purpose, so http, https and www variants of the same link all verify.

PHP

$path = '/s/end/complete?rdid=' . $rdid;
$url = 'https://researchdart.com' . $path . '&h=' . hash_hmac('sha256', $path, $secret);

Python

import hashlib, hmac

path = f"/s/end/complete?rdid={rdid}"
signature = hmac.new(secret.encode(), path.encode(), hashlib.sha256).hexdigest()
url = f"https://researchdart.com{path}&h={signature}"

Node.js

const crypto = require('crypto');

const path = `/s/end/complete?rdid=${rdid}`;
const signature = crypto.createHmac('sha256', secret).update(path).digest('hex');
const url = `https://researchdart.com${path}&h=${signature}`;

The rule that matters

Never compute the signature in the respondent's browser. If the secret sits in JavaScript on the survey page, anyone can read it in developer tools and sign any URL they like. You have then added complexity and removed no risk.

The signature has to come from a server: your survey platform's server-side scripting, your own backend, or a small signing service the survey calls. If your platform has none of these, do not fake it. Turn signing off for that project and report outcomes with the status API from a system you control. That gives the same protection, because the respondent never sees the request. Postbacks versus redirects covers the trade-offs.

Rotating secrets

Treat signing secrets as passwords. Keep them in the platform's secret storage, not in survey text. Rotate them when someone with access leaves. On ResearchDart rotation takes effect immediately, so update the survey first, rotate second, and run a sandbox session straight after.

When signatures fail

Nearly every rejected signature comes down to one of these:

  • Parameters after h. The signature must be the last thing in the URL.
  • Encoding differences. Sign exactly the string that will appear in the URL. If a value is URL-encoded in the link, sign the encoded form.
  • The domain was signed. Start at the path.
  • A stale secret after rotation.
  • Uppercase hex from a library with different defaults.

Is it worth it?

On a consumer study paying a dollar a complete, a determined respondent editing URLs is a nuisance. On a B2B or healthcare study paying many times that, the incentive to forge a complete is real and the fix is an afternoon. We would sign every project where the survey platform can do it server-side, and use the status API everywhere else.

Questions readers ask

Do signed links stop bots from taking surveys?
No. Signatures stop forged or edited redirect URLs. Bots and AI agents that genuinely click through a survey need pre-survey screening, in-survey checks and minimum completion times.
Can I sign links in Qualtrics or similar tools?
Only if the tool can run code on its servers or call an external service server-side. Never put the secret in browser JavaScript. Otherwise report outcomes with the status API.
Why is the domain not part of the signature?
So the same link verifies over http or https and with or without www. The path, query and secret still protect the outcome and the session ID.
Sample routing Allocations, signed links, outcomes, redirects and postbacks.