Compliance
GDPR consent pattern for WordPress forms
Most form GDPR setups are theater. Here's the pattern that holds up to a real audit, with the consent fields, the storage, and the audit trail.
Most WordPress form GDPR setups are theater. A “I agree to the privacy policy” checkbox, no record of which version they agreed to, no audit trail, no way to honor a deletion request without a database query.
If a regulator audits your site (or, more realistically, a customer asks “what data do you have on me?”), the theater falls apart fast.
Here’s the pattern that holds up.
What GDPR actually requires for forms
Five things, briefly:
1. Lawful basis. You need a legal reason to process the data. For contact forms, that’s usually “legitimate interest” (someone is contacting you, they want a response). For newsletter signups, it’s consent.
2. Specific consent. “Click here to agree to everything” doesn’t cut it. Each thing the user agrees to needs a separate, opt-in checkbox.
3. Audit trail. When the user agreed, what they agreed to, what version of the privacy policy was in effect.
4. Right to access. The user can ask “what do you have on me?” and you have to deliver it within 30 days.
5. Right to deletion. The user can ask “delete me” and you have to honor it within 30 days, plus prove you did.
For a typical contact form, the first three matter. Right to access and deletion are workflow problems, not form problems.
The form fields that actually work
A compliant contact form needs three checkboxes (or fewer, depending on what you do):
<p>
<label>
<input type="checkbox" name="consent_contact" required value="yes" />
I consent to my data being used to respond to my inquiry.
<span class="cf-required">*</span>
</label>
</p>
<p>
<label>
<input type="checkbox" name="consent_marketing" value="yes" />
Send me occasional product updates and tips.
(Optional, you can unsubscribe any time.)
</label>
</p>
<p>
<label>
<input type="checkbox" name="consent_privacy_policy" required value="yes" />
I have read the <a href="/privacy/" target="_blank">privacy policy</a>.
<span class="cf-required">*</span>
</label>
</p>
Three checkboxes, two required. The marketing one is opt-in (unchecked by default). That’s the GDPR cornerstone: marketing consent must be a deliberate action.
What you should not do
Don’t pre-check the marketing consent box. Pre-checked boxes invalidate consent under GDPR. Every audit catches this.
Don’t bundle “agree to privacy policy + receive marketing” into one checkbox. Specific consent means each thing gets its own.
Don’t auto-add users to a newsletter from a contact form. They didn’t ask. That’s a separate flow with its own consent.
Don’t submit “agreed to privacy policy” as a hidden field that’s always ‘yes’. That’s not consent, that’s pretending. If a user submits the form, they have to actually tick the box.
The audit trail
Every submission needs a snapshot of what the user agreed to. Core Forms stores submissions with full data including consent fields, plus metadata: timestamp, IP, user agent, page URL.
A real audit trail looks like this:
{
"name": "Jane Smith",
"email": "jane@example.com",
"message": "...",
"consent_contact": "yes",
"consent_marketing": "yes",
"consent_privacy_policy": "yes",
"_meta": {
"submitted_at": "2026-04-15T14:30:42Z",
"ip_address": "203.0.113.4",
"user_agent": "Mozilla/5.0 ...",
"referer_url": "https://yoursite.com/contact/"
}
}
You can answer “what did this user consent to and when?” by looking at the row.
Privacy policy versioning
If your privacy policy changes, the audit trail needs to know which version they consented to. The simple way: when the policy updates, increment a version number, and add a hidden field to the form:
<input type="hidden" name="privacy_policy_version" value="2026-04-15" />
Now every submission records the policy version in effect at submission time. If a user asks “what privacy terms did I agree to?”, you can pull up that version.
Most GDPR audits don’t dig this deep. But if a customer disputes a marketing email, the version tag is the difference between “we have the proof” and “we’d have to guess.”
Right to access (data export)
When a user asks “what data do you have on me?”, you need to:
- Find every submission with their email.
- Export it in a portable format (JSON, CSV).
- Send it within 30 days.
Core Forms’ submissions admin supports search by email. CSV export per-form is built in. For a real “right to access” request, you can:
- Search submissions by email across all forms.
- Export the matching rows to CSV.
- Email the user a copy.
For sites with high submission volume, automate this with a REST API endpoint that returns all submissions for a given email. Useful for a self-service “download my data” feature on the user’s account page.
Right to deletion
When a user asks “delete me”:
- Find every submission from their email.
- Delete the rows.
- Confirm the deletion.
- Cascade: also remove them from any CRM or Mailchimp audience they were pushed to.
Core Forms can delete submissions in bulk. The cascade to external tools is on you — there’s no “delete from Mailchimp” magic. For each integration the user landed in, you have to manually unsubscribe / delete them.
This is where the integration sprawl matters. If a single form pushed leads to Mailchimp + HubSpot + Notion + Airtable, a deletion request requires action in five places. Document the flow before a request lands.
The data retention policy
GDPR doesn’t mandate a specific retention period, but it does require you to define one and stick to it.
For contact-form submissions, my default is:
- Active leads (responded to): keep until the relationship ends or until the user requests deletion.
- Inactive leads (no response, no engagement): keep for 12 months, then delete.
- Spam submissions: delete after 30 days.
Core Forms can auto-clean old submissions on a schedule. Settings → Submission limit → Retention. Define the policy once, the cleanup runs in the background.
Where Core Forms helps
Three things specifically:
1. Submission storage with full metadata. IP, timestamp, referrer, user agent — all stored automatically. The audit trail is built without extra work.
2. CSV export and REST API. Right-to-access requests can be answered programmatically.
3. Bulk deletion. Right-to-deletion can be honored without database surgery.
What Core Forms doesn’t do:
- Generate a privacy policy. (Use Termly, iubenda, or write one.)
- Enforce consent before form load. (That’s a cookie banner’s job. Cookiebot, OneTrust, etc.)
- Cascade-delete from external tools. (You wire each integration’s delete flow yourself.)
GDPR compliance is a workflow problem, not a plugin feature. Core Forms gives you the data layer; the policy and process are still yours to build.
The next step
Pick one form. Audit:
- Are there separate checkboxes for contact consent, marketing consent, privacy policy?
- Is the marketing checkbox unchecked by default?
- Is the form storing IP, timestamp, and referrer?
- Do you have a documented retention period?
If any answer is “no,” fix it before the next regulator email.
Submission storage and metadata are bundled at every plan level. Pricing.