Most small SaaS founders in the EU know they need GDPR compliance. Most also think it requires a €10K legal audit, a consent management platform, and a full-time DPO. It doesn't — not at the small scale.
I've set up GDPR compliance for 6 client projects. Here's the minimum viable setup that takes about 5 hours and covers what actually matters.
What GDPR actually requires (the short version)
- Lawful basis for processing: You need a legal reason to collect data. For SaaS: consent (for marketing) or contract performance (for the service itself).
- Transparency: Tell users what you collect, why, and how long you keep it.
- Data minimization: Don't collect more than you need.
- Right to access/delete: Users can request their data or its deletion.
- Security: Protect the data you hold.
- Breach notification: Report breaches to the authority within 72 hours.
That's it. Everything else (DPO, DPIA, records of processing) has thresholds that small SaaS rarely meets.
The 5-hour setup
Hour 1: Privacy policy (the real one)
Not a legal template copied from a Fortune 500 company. A plain-language document that covers:
- What you collect: email, name, usage analytics, payment data (via Stripe — you don't store cards)
- Why you collect it: to provide the service, send transactional emails, improve the product
- Who you share with: Stripe (payments), Vercel (hosting), Sentry (error tracking), PostHog or Plausible (analytics)
- How long you keep it: active account data retained while account exists, deleted within 30 days of account deletion
- User rights: access, correction, deletion, data portability, objection to processing
- Contact: email address for data requests
Write it in plain language. Not legalese. A user should understand what happens to their data in 2 minutes of reading.
Hour 2: Cookie consent (minimal)
If you use only essential cookies (session, authentication), you don't need a cookie banner at all under GDPR. Essential cookies have an exemption.
If you use analytics (PostHog, Google Analytics, Plausible):
- Plausible and Fathom: Cookie-free analytics. No banner needed.
- PostHog with cookie-free mode: No banner needed if configured without cookies.
- Google Analytics: Requires consent. You need a banner.
My recommendation: use Plausible or PostHog in cookie-free mode and skip the cookie banner entirely. The banner costs you 5–15% of analytics accuracy (users who decline) and adds UX friction.
If you must have a banner, keep it simple: two buttons ("Accept" / "Reject"), no dark patterns, no pre-checked boxes.
Hour 3: Data deletion flow
When a user deletes their account, you need to actually delete their data. Not soft-delete — hard delete from the database.
async function deleteUserData(userId: string) {
// 1. Cancel any active subscriptions
await stripe.subscriptions.cancel(user.stripeSubscriptionId)
// 2. Delete from your database
await db.transaction(async (tx) => {
await tx.delete(sessions).where(eq(sessions.userId, userId))
await tx.delete(preferences).where(eq(preferences.userId, userId))
await tx.delete(activities).where(eq(activities.userId, userId))
await tx.delete(users).where(eq(users.id, userId))
})
// 3. Remove from third-party services
await posthog.deleteUser(userId)
await sentry.deleteUser(userId)
// 4. Log the deletion (without PII)
logger.info('User data deleted', { userId, timestamp: new Date() })
}
The deletion log (step 4) is your proof that you complied. Keep it for 3 years.
Hour 4: Data export endpoint
GDPR gives users the right to receive their data in a machine-readable format. Build one endpoint:
// app/api/user/export/route.ts
export async function GET(request: Request) {
const user = await getAuthenticatedUser(request)
const data = {
profile: await db.query.users.findFirst({ where: eq(users.id, user.id) }),
preferences: await db.query.preferences.findMany({
where: eq(preferences.userId, user.id),
}),
activities: await db.query.activities.findMany({
where: eq(activities.userId, user.id),
}),
}
// Remove internal fields
delete data.profile.passwordHash
delete data.profile.stripeCustomerId
return new Response(JSON.stringify(data, null, 2), {
headers: {
'Content-Type': 'application/json',
'Content-Disposition': `attachment; filename="user-data-${user.id}.json"`,
},
})
}
JSON is a valid machine-readable format. You don't need CSV or XML.
Hour 5: Third-party audit
List every service that touches user data. For each one:
| Service | Data it receives | DPA signed? | EU hosting? |
|---|---|---|---|
| Stripe | Email, name, payment | Yes (standard) | EU data residency available |
| Vercel | IP addresses (logs) | Yes (DPA in ToS) | EU region selectable |
| Sentry | IP, error context | Yes (DPA available) | EU data region |
| Plausible | None (cookie-free) | N/A | EU-hosted |
| Resend | Email addresses | Yes (DPA available) | Check region |
DPA = Data Processing Agreement. Most SaaS providers have one. You need to sign it — usually just checking a box in their dashboard.
If a service doesn't offer a DPA or EU hosting, consider switching. For small SaaS, this is usually Resend vs SendGrid territory — both offer DPAs.
What you can skip (at small scale)
- Data Protection Officer: Required only if your core activity involves systematic monitoring of individuals at large scale. A 500-user SaaS doesn't qualify.
- Data Protection Impact Assessment: Required only for high-risk processing (biometric data, large-scale profiling). Standard SaaS doesn't qualify.
- Records of Processing Activities: Technically required for companies with 250+ employees or high-risk processing. But keeping a simple spreadsheet of "what data, why, how long" is good practice anyway.
- Cookie consent platform (Cookiebot, OneTrust): Overkill if you use cookie-free analytics. The platform itself costs more per year than the compliance value it provides.
The ongoing maintenance
GDPR isn't a one-time setup. Monthly:
- Respond to data requests within 30 days (you'll get ~0 per month at small scale)
- Review new third-party integrations before adding them
Quarterly:
- Verify the data deletion flow still works
- Check that your DPAs are current
Annually:
- Update the privacy policy if your data practices changed
- Review data retention — delete what you no longer need
The cost of not doing it
A GDPR fine for a small company starts at €10K–€50K. More realistically, your first penalty would be a warning from the supervisory authority. But the real cost is losing a B2B deal because the buyer's procurement team sees no privacy policy and no DPA.
5 hours of setup. Zero ongoing cost if you use cookie-free analytics. And a privacy page that actually makes sense to real humans.
Need GDPR compliance set up for your SaaS? Let's talk — I include this in every EU-facing project I build.