All articles Industry

Survey Panel Fraud: Professional Respondents and Bot Completes

Paid surveys have a simple incentive problem. Respondents get paid per complete, and the people commissioning the research can’t see who’s answering. That attracts three kinds of bad data: the same person answering many times, people pretending to be somewhere (or someone) they’re not to qualify for better-paid studies, and scripts generating completes at volume.

All three damage the dataset in ways that are hard to see afterwards. A survey with a duplicated cohort looks like a survey with a strong opinion. This post covers how each pattern works and which signals catch it before the complete is accepted.

The three patterns

Duplicate respondents

A professional respondent joins several panels, or holds several accounts on one, and takes the same survey through each of them. Survey routing makes it easy: a study sourced from multiple suppliers can reach the same person through two or three different doors. Each entry carries a different respondent id, so supplier-side deduplication doesn’t catch it.

Location and profile fakers

Studies targeting a specific country, region or demographic often pay more and have smaller pools. Respondents outside the target use VPNs or residential proxies to appear local and answer screeners to match the profile. The answers are then real human answers from the wrong population, which is arguably worse than noise.

Scripted and AI-assisted completes

Scripts that move through surveys, select plausible answers and paste text into open-ends. Increasingly, the open-ended answers come from a language model: fluent, on-topic, and generic. Some farms combine human workers with automation, using scripts for the grid questions and people for the screeners.

Gate the entry, not just the complete

Most fraud checks in survey research happen afterwards: quality reviews of speeders, straight-liners and gibberish open-ends. Those still matter. But by then the respondent has been paid, the quota cell may be full, and removing them means re-fielding.

A better pattern is an entry gate: a short landing page you control, between the panel link and the survey itself. It identifies the device, checks it against everyone who has already entered this study, and only then redirects into the survey.

<script src="https://api.pryntid.com/cdn/prynt.umd.js"></script>
<script>
  const params = new URLSearchParams(location.search);
  Prynt.load({ apiKey: 'pk_live_…' })
    .then((p) => p.identify({
      tag: { action: 'survey_entry', study: params.get('study'), source: params.get('src') },
      linkedId: params.get('rid'),             // the panel's respondent id
    }))
    .then(({ requestId }) => fetch('/gate', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ requestId, study: params.get('study'), rid: params.get('rid') }),
    }))
    .then((r) => r.json())
    .then(({ redirect }) => location.replace(redirect));
</script>

The server makes the decision, using the secret key:

app.post('/gate', async (req, res) => {
  const { requestId, study, rid } = req.body;
  const event = await prynt.getEvent(requestId);           // @prynt/node
  const ss = event.smartSignals;

  const seen = await db.entries.exists({ study, visitorId: event.visitorId });
  const target = await db.studies.targetCountry(study);
  const country = event.ipLocation?.country;
  const geoMismatch = target && country && country !== target;
  const masked = ss.vpn?.result || ss.residentialProxy?.result || ss.locationSpoofing?.result;

  let outcome = 'enter';
  if (seen) outcome = 'duplicate';
  else if (event.decision === 'block' || ss.bot?.result || ss.aiAgent?.result) outcome = 'automation';
  else if (geoMismatch || (target && masked)) outcome = 'geo';

  await db.entries.insert({ study, rid, visitorId: event.visitorId, outcome, requestId });
  res.json({ redirect: outcome === 'enter' ? surveyUrl(study, rid) : terminateUrl(study, rid, outcome) });
});

Three things to note:

  • Dedupe per study by visitorId, not by respondent id. That’s what catches the same person arriving through two suppliers with two different ids.
  • Pass the panel’s respondent id as linkedId. Over time, accountsOnDevice shows how many respondent ids one device has used across all your studies. A device with a dozen panel identities is a professional respondent, regardless of whether they’re a duplicate in this particular study.
  • Terminate cleanly. Send rejected entries to your normal terminate or quality-fail link so the supplier is informed through the usual channel, and don’t tell the respondent which check failed.

Geo mismatch, done carefully

Location checks are where survey fraud screening most often hurts real respondents. A traveler, an expat or someone on a work VPN can fail a strict IP-country rule. A few principles:

  • Use the network country as one input. ipLocation.country from the event is the starting point.
  • Weight masking only when location matters. VPN and proxy signals are context, not a verdict. For a global study, a VPN means little. For a study that pays more because it targets one country, a VPN or residential proxy combined with a mismatched timezone or browser language is a strong tell.
  • Look for contradictions, not just distance. Prynt’s locationSpoofing signal rolls up disagreements between what the device claims and what the network shows. Timezone and locale mismatch detection covers how those contradictions differ from honest travel.

Fill cadence and automation

Scripts and assisted farms leave timing traces. The agent’s protectForm(form) adds honeypot fields and timing signals to a form, and the server reports formBot when they indicate a scripted fill. In longer surveys, look at:

  • Time per page compared with the median. Speeders are a known quality issue; uniform, machine-regular timing is a different and more suspicious one.
  • Paste-heavy open-ends. A long, fluent open-ended answer that appeared in one paste event, in a few seconds, is worth a second look, especially if the aiAgent signal fired at entry.
  • Automation signals such as headless browsers and non-browser TLS fingerprints, which show up as the BOT and TLS_AUTOMATION reason codes.

Form-fill cadence signals explains the timing side in detail.

Close the loop with suppliers

Keep a per-supplier report: entries, duplicates, geo fails and automation fails. A supplier whose traffic is mostly clean gets more quota; one whose traffic is a quarter duplicates gets a conversation. The device data turns a vague “your sample quality is low” into specific numbers.

When post-field quality review removes respondents your gate let through, report them: POST /v1/outcomes with the label fraud or bot and the entry’s requestId marks the device, so it carries KNOWN_ABUSER at its next entry. Because a lot of respondents share home and mobile networks, prefer labeling by visitorId when the problem was the person rather than the network.

Survey incentives are a close cousin of other paid-action programs; see incentivized traffic abuse for the wider pattern. Put an entry gate in front of your next study, dedupe by device across all sample sources, and compare the duplicate rate per supplier when fielding closes.

Try it free

Prynt is device intelligence with a free tier — visitor IDs, bot & fraud Smart Signals, and behavioral biometrics, powered by a cross-site network. Start free.

Keep reading