GDPR for a French B2B SaaS: The Complete Checklist, No Myths
What you actually have to do to be GDPR-compliant as a French B2B SaaS, and what compliance agencies sell you that you don't need.
This article is written from the French market's perspective (CNIL guidance, French B2B practice), but the substance applies to any B2B SaaS operating under the EU's GDPR, whatever country you're building from.
The myth of GDPR complexity
If you're launching a SaaS in France, you've probably come across agencies pitching GDPR audits for €3,000-15,000. For 80% of early-stage B2B SaaS products, that's unnecessary.
This article separates what's mandatory from what's expensive consulting. No bullshit, no audit recommendation. Just what actually needs doing.
⚠️ Disclaimer: I'm not a lawyer. This article is an operational guide based on CNIL texts and real French B2B SaaS practice. For edge cases, consult a certified DPO.
Step 1: Identify personal data
GDPR applies to "personal data": anything that can identify a natural person, directly or indirectly.
In a typical B2B SaaS:
// Personal data
const personalData = {
user: ["email", "name", "phone", "ipAddress"],
customer: ["contactPerson", "contactEmail"],
employee: ["fullName", "email", "salary", "address"],
// Indirect, but still PII
metadata: ["lastLoginAt", "userAgent", "sessionId"],
};
// NOT personal data (B2B)
const notPersonal = {
company: ["companyName", "siret", "vatNumber"],
// ⚠️ except for a sole proprietorship, where companyName IS a natural person
invoice: ["amount", "description", "issueDate"],
};Classic trap: a sole proprietorship's business ID is personal data (it identifies an individual). An LLC's business ID is not.
Step 2: The 7 actually mandatory obligations
1. An accessible privacy policy
A /en/politique-de-confidentialite page listing:
- What data you collect
- Why (the purpose)
- How long you keep it (retention period)
- Who you share it with (subprocessors)
- How to export / delete it
Minimal template:
## Data we collect
While using {App}, we collect:
- **Identification data**: email, first and last name (purpose: auth, support)
- **Technical data**: IP, user agent, logs (purpose: security, debugging)
- **Business data**: what you enter into the app (purpose: contract performance)
## Retention period
- Active account: for as long as you use the service
- Inactive account: 3 years after last login
- Technical logs: 6 months
- Billing data: 10 years (accounting obligation)
## Your rights
You can request at any time:
- Access to your data (JSON export)
- Rectification
- Deletion
- Portability (structured export)
Contact: dpo@yoursaas.com2. Consent for non-essential cookies
// HeartCo pattern: consent banner
const consentTypes = {
essential: { required: true, default: true }, // session, CSRF
analytics: { required: false, default: false }, // Vercel Analytics, Plausible
marketing: { required: false, default: false }, // Meta Pixel, Google Ads
};What a lot of teams get wrong: analytics are NOT "essential." Plausible and Vercel Analytics should be off by default, or use their "cookieless" mode, which doesn't require consent.
3. The register of processing activities
GDPR Article 30. A Google Doc or a compliance/processing-register.md file in your repo is enough.
Minimum content for each processing activity:
## User authentication
- **Purpose**: allow access to the service
- **Data categories**: email, hashed password
- **Legal basis**: contract performance
- **Recipients**: HeartCo team (admin only)
- **Subprocessors**: Supabase (DB hosting), Vercel (app hosting)
- **Retention**: 3 years after last login
- **Transfers outside the EU**: none4. The right to export and deletion
tRPC implementation:
// src/server/api/routers/rgpd.ts
export const rgpdRouter = createTRPCRouter({
exportMyData: protectedProcedure.mutation(async ({ ctx }) => {
const userId = ctx.session.user.id;
const data = {
user: await ctx.db.user.findFirst({ where: { id: userId } }),
organizations: await ctx.db.organization.findMany({
where: { members: { some: { userId } } },
}),
invoices: await ctx.db.invoice.findMany({
where: { createdById: userId },
}),
// ... every table linked to the user
};
// Resend email with the JSON attached
await resend.emails.send({
to: ctx.session.user.email,
subject: "Your HeartCo data",
attachments: [
{
filename: "export.json",
content: Buffer.from(JSON.stringify(data, null, 2)),
},
],
// ... React Email template
});
return { sent: true };
}),
deleteMyAccount: protectedProcedure
.input(z.object({ confirmEmail: z.string().email() }))
.mutation(async ({ ctx, input }) => {
if (input.confirmEmail !== ctx.session.user.email) {
throw new TRPCError({ code: "BAD_REQUEST" });
}
// Soft delete + anonymization
await ctx.db.user.update({
where: { id: ctx.session.user.id },
data: {
email: `deleted-${ctx.session.user.id}@deleted.local`,
name: "Deleted user",
deletedAt: new Date(),
},
});
}),
});Legal deadline: one month maximum to respond. For a SaaS, automate it: one click in /dashboard/settings/rgpd and the user gets their export by email in under 5 minutes.
5. Data security (Article 32)
// Minimum technical measures
const securityMeasures = {
encryption: {
inTransit: "TLS 1.3 (Vercel default)",
atRest: "AES-256 (Supabase default)",
passwords: "bcrypt rounds >= 12",
},
access: {
multiTenant: "Prisma $extends auto-scope",
rbac: "Permission matrix",
audit: "Log of every admin action",
},
backup: {
frequency: "daily",
retention: "30 days",
location: "EU (Supabase)",
},
};6. Subprocessor contracts (DPAs)
GDPR Article 28. For every subprocessor that processes data on your behalf, you need a signed Data Processing Agreement.
Typical SaaS subprocessors and their DPAs:
| Service | DPA | Hosting |
|---|---|---|
| Vercel | vercel.com/legal/dpa | Frankfurt, Dublin (EU) |
| Supabase | supabase.com/legal/dpa | Frankfurt (EU) |
| Stripe | Dashboard → Compliance | Ireland (EU) |
| Resend | Dashboard → Privacy | Frankfurt (EU) |
| Mistral AI | Dashboard | Paris (EU) |
| Pusher | Dashboard → Legal (acquired by MessageBird) | Configurable cluster, pick EU |
| Upstash Redis | upstash.com/trust/dpa.pdf | US (Delaware) ⚠️ SCCs required |
| OpenAI | Dashboard (US DPA) | United States ⚠️ |
Practical rule
Favor EU-based subprocessors. For US ones (OpenAI, Slack), you have to document the transfer via SCCs (Standard Contractual Clauses).
7. Breach notification (Article 33)
If a data breach happens, you have 72 hours to notify the CNIL via notifications.cnil.fr (or your own country's supervisory authority, if you're outside France).
Prepare an incident-response template:
# Incident #X: Date
## Facts
- What: description of the leak
- When: detection timestamp
- How many: number of people affected
- What data: email + ... (not the hashed password, if using bcrypt)
## Immediate actions
- Patch deployed: SHA + time
- Tokens revoked / sessions invalidated
- User communication: email + status page
## Corrective measures
- Test added: ...
- Process changed: ...What's NOT mandatory (but gets sold to you anyway)
❌ A certified DPO: only mandatory if you process sensitive data at scale (health, justice, surveillance). For 99% of B2B SaaS, an internal GDPR point of contact is enough.
❌ A €5,000 GDPR audit: unnecessary at an early stage. Do your own self-assessment with the CNIL's checklist (free).
❌ HDS-certified hosting: only if you process health data.
❌ ISO 27001: not a GDPR requirement. It's a certification that reassures large enterprise customers, not a legal obligation.
The CNIL scenario
If the CNIL audits your SaaS:
- You receive an official letter or email
- You have ~30 days to respond with your documentation
- The CNIL evaluates based on your good faith and proportionality
What protects you:
- An up-to-date processing register (even in markdown, in Git)
- A clear privacy policy
- Export and deletion rights actually implemented
- Signed subprocessor DPAs
- Breach notification under 72h (when applicable)
You do NOT need an ISO certification, an external audit, or an €80k/year DPO to be compliant. You need to be organized.
Condensed checklist
- Privacy policy published at
/en/politique-de-confidentialite - Cookie banner with granular consent (essential by default, everything else opt-in)
- Up-to-date processing register (
compliance/register.mdin the repo) - "Export my data" button in the user dashboard
- "Delete my account" button with email confirmation
- DPAs signed with every subprocessor
- Log retention kept short (6 months max for technical logs)
- TLS everywhere (Vercel does this), bcrypt rounds >= 12
- Auditable multi-tenant isolation (Vitest tests)
- Incident-response template ready
- An active
dpo@orprivacy@contact
Conclusion
GDPR for a French B2B SaaS is 2 days of proper setup, not 6 months of paperwork. Once it's in place, it maintains itself in about an hour a month.
In HeartCo, these patterns are wired in by default: an editable /en/politique-de-confidentialite page, a /dashboard/settings/rgpd route with export and delete, auto-scoped multi-tenancy, a compliant cookie banner. You go to production already compliant.
Go further
Related articles
Electronic Invoicing 2026 for a B2B SaaS in France
Official timeline, PDP and e-reporting vocabulary, generating a Factur-X, and the role of a connector like iopole for a French B2B SaaS.
ReadIntegrating Stripe in a French SaaS: VAT, Invoices, Webhooks
A complete guide to integrating Stripe in a French B2B SaaS: VAT handling, compliant invoices, secured webhooks, and subscriptions.
ReadSteering Claude Code with CLAUDE.md on a Multi-Tenant SaaS
The real rules that govern this SaaS with Claude Code: what goes in CLAUDE.md, what doesn't, and what's actually shipped at purchase.
ReadReady to launch your SaaS?
HeartCo Starter includes everything you need: auth, payments, AI, mobile, audited security. Starting at $219.