Skip to main content
All articles
8 min read

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.com
// 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**: none

4. 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:

ServiceDPAHosting
Vercelvercel.com/legal/dpaFrankfurt, Dublin (EU)
Supabasesupabase.com/legal/dpaFrankfurt (EU)
StripeDashboard → ComplianceIreland (EU)
ResendDashboard → PrivacyFrankfurt (EU)
Mistral AIDashboardParis (EU)
PusherDashboard → Legal (acquired by MessageBird)Configurable cluster, pick EU
Upstash Redisupstash.com/trust/dpa.pdfUS (Delaware) ⚠️ SCCs required
OpenAIDashboard (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:

  1. You receive an official letter or email
  2. You have ~30 days to respond with your documentation
  3. 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.md in 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@ or privacy@ 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

Share

Ready to launch your SaaS?

HeartCo Starter includes everything you need: auth, payments, AI, mobile, audited security. Starting at $219.

30-day money-back guarantee
GDPR for a French B2B SaaS: The Checklist | HeartCo