
Privacy Notice Generator
- 47 installs
- 451 repo stars
- Updated July 21, 2026
- borghei/claude-skills
Privacy Notice Generator is a Claude skill that scaffolds GDPR-compliant privacy notices for EU/EEA jurisdictions and scores existing notices against Art. 13/14 requirements.
About
Privacy Notice Generator drafts GDPR-compliant privacy notices for EU/EEA jurisdictions and verifies existing notices against Art. 13/14 requirements. A developer or compliance owner uses it to scaffold a 13-section notice for a chosen notice type and jurisdiction, then score it 0-100 with missing and incomplete elements flagged. It supports 6 notice types and 9 jurisdictions and is marked experimental, not legal advice.
- Scaffolds a 13-section notice with jurisdiction-specific placeholders
- Supports 6 notice types across 9 EU/EEA jurisdictions
- Compliance checker scores a notice 0-100 against Art. 13/14 GDPR
Privacy Notice Generator by the numbers
- 47 all-time installs (skills.sh)
- Ranked #1,355 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
privacy-notice-generator capabilities & compatibility
- Capabilities
- privacy compliance · security audit · terms generator
- Use cases
- security audit · documentation
- Pricing
- Free
What privacy-notice-generator says it does
Draft GDPR-compliant privacy notices for EU/EEA jurisdictions. Supports 6 notice types, 9 jurisdictions, multi-layer compliance verification.
Validates a privacy notice text against Art. 13/14 GDPR requirements and generates a compliance score with missing/incomplete elements.
**Supported Jurisdictions:** DE, FR, AT, IT, ES, NL, BE, IE, UK
npx skills add https://github.com/borghei/claude-skills --skill privacy-notice-generatorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 47 |
|---|---|
| repo stars | ★ 451 |
| Last updated | July 21, 2026 |
| Repository | borghei/claude-skills ↗ |
What it does
Draft a GDPR-compliant privacy notice for an EU/EEA jurisdiction and score an existing notice against Art. 13/14 requirements.
Who is it for?
Producing or auditing a GDPR privacy notice for a specific EU/EEA jurisdiction and audience.
Skip if: Non-EU privacy regimes or binding legal sign-off; it is experimental and not legal advice.
When should I use this skill?
Drafting a privacy notice, checking notice compliance, or mapping jurisdiction-specific requirements.
What you get
A jurisdiction-specific 13-section privacy notice plus a 0-100 compliance score listing missing and incomplete elements.
- 13-section privacy notice draft
- 0-100 compliance score with gaps
By the numbers
- 6 notice types
- 9 jurisdictions
- 13-section notice structure
Files
⚠️ EXPERIMENTAL — This skill is provided for educational and informational purposes only. It does NOT constitute legal advice. All responsibility for usage rests with the user. Consult qualified legal professionals before acting on any output.
Privacy Notice Generator
Tools and guidance for drafting GDPR-compliant privacy notices across EU/EEA jurisdictions and audience types, with multi-layer compliance verification.
---
Table of Contents
- Tools
- Privacy Notice Scaffolder
- Notice Compliance Checker
- Reference Guides
- Workflows
- Troubleshooting
- Success Criteria
- Scope & Limitations
- Anti-Patterns
- Tool Reference
---
Tools
Privacy Notice Scaffolder
Generates a privacy notice skeleton with all required sections pre-populated with jurisdiction-specific placeholders and legal references.
# Website privacy notice for German jurisdiction
python scripts/privacy_notice_scaffolder.py \
--notice-type website \
--jurisdiction DE \
--data-categories personal,contact,usage,cookies \
--legal-bases consent,contract,legitimate_interests \
--has-cookies \
--has-international-transfers
# Employee notice for French jurisdiction with AI processing
python scripts/privacy_notice_scaffolder.py \
--notice-type employee \
--jurisdiction FR \
--data-categories personal,employment,financial,health \
--legal-bases contract,legal_obligation,consent \
--has-ai
# B2C customer notice for UK with all features
python scripts/privacy_notice_scaffolder.py \
--notice-type b2c \
--jurisdiction UK \
--data-categories personal,contact,financial,usage,marketing \
--legal-bases consent,contract,legitimate_interests \
--has-cookies --has-ai --has-international-transfers \
--jsonSupported Notice Types:
| Type | Audience | Key Sections |
|---|---|---|
| website | Website/app visitors | Cookies, analytics, tracking technologies |
| applicant | Job applicants | Recruitment data, talent pool, retention periods |
| employee | Employees | Works council, IT monitoring, BYOD, HR data |
| b2b | Business partners | Art. 14 requirements, source disclosure |
| b2c | B2C customers | Soft opt-in, payment processing, loyalty |
| combined | Multiple audiences | Merged sections with audience-specific callouts |
Supported Jurisdictions: DE, FR, AT, IT, ES, NL, BE, IE, UK
13-Section Notice Structure: 1. Controller identity and contact 2. DPO contact details 3. Data categories collected 4. Purposes and legal bases 5. Recipients and categories 6. International transfers 7. Retention periods 8. Data subject rights 9. Right to withdraw consent 10. Right to complain to SA 11. Automated decision-making 12. Cookies and tracking (if applicable) 13. AI processing (if applicable)
---
Notice Compliance Checker
Validates a privacy notice text against Art. 13/14 GDPR requirements and generates a compliance score with missing/incomplete elements.
# Check a privacy notice file
python scripts/notice_compliance_checker.py privacy_notice.md
# Check with jurisdiction-specific requirements
python scripts/notice_compliance_checker.py privacy_notice.md --jurisdiction DE
# Check with notice type for type-specific validation
python scripts/notice_compliance_checker.py privacy_notice.md \
--jurisdiction DE --notice-type employee
# JSON output
python scripts/notice_compliance_checker.py privacy_notice.md \
--jurisdiction FR --notice-type website --jsonChecks For:
| Category | Elements Checked |
|---|---|
| Art. 13 Mandatory | Controller identity, DPO contact, purposes, legal bases, recipients, transfers, retention, all 8 rights, automated decisions, consent withdrawal, SA complaint |
| Art. 14 Additional | Source of data, categories obtained (for indirect collection) |
| General | Art. 21 right to object prominence, plain language, no placeholders, consistent formatting |
| Jurisdiction-specific | DE: Widerspruchsrecht prominence, TDDDG; FR: CNIL recommendations; UK: ICO guidance |
Output:
- Compliance score (0-100)
- Missing elements (must-fix)
- Incomplete elements (should-improve)
- Jurisdiction-specific findings
- Type-specific findings
---
Reference Guides
Notice Types Guide
references/notice_types_guide.md
Detailed guidance for 6 notice types:
- Platform sub-types for website/app notices
- Applicant-specific data categories and retention
- Employee notice with works council and monitoring requirements
- B2B Art. 14 requirements and source disclosure
- B2C soft opt-in and payment processing
- Combined notice merge strategies
Jurisdiction Requirements
references/jurisdiction_requirements.md
Jurisdiction-specific requirements for 9 jurisdictions:
- SA details and registration requirements
- Requirements beyond GDPR baseline
- Standard wording recommendations
- Retention guidance per jurisdiction
Compliance Verification
references/compliance_verification.md
5-layer verification system:
- Jurisdiction-specific checks
- Art. 13/14 mandatory disclosures
- General compliance checks
- Type-specific checks
- AI Act compliance
- Post-generation checklist
- Writing style guide
---
Workflows
Workflow 1: SCOPE → INTAKE → DRAFT → VERIFY → DELIVER
Step 1: SCOPE — Determine notice parameters
→ Notice type (website/applicant/employee/b2b/b2c/combined)
→ Jurisdiction (DE/FR/AT/IT/ES/NL/BE/IE/UK)
→ Special features (cookies, AI, international transfers)
Step 2: INTAKE — Gather information
→ Controller identity and DPO
→ Data inventory (categories, sources)
→ Purposes and legal bases per category
→ Recipients and processors
→ Transfer destinations and mechanisms
→ Retention periods per category
→ Cookie/tracking inventory (if website)
→ AI processing details (if applicable)
Step 3: DRAFT — Generate notice skeleton
→ python scripts/privacy_notice_scaffolder.py [params]
→ Fill in placeholders with actual information from intake
→ Add jurisdiction-specific clauses
→ Apply writing style guide (you/your, short sentences, tables)
Step 4: VERIFY — Run compliance checker
→ python scripts/notice_compliance_checker.py notice.md --jurisdiction [J] --notice-type [T]
→ Address all missing elements
→ Address incomplete elements
→ Review jurisdiction-specific findings
Step 5: DELIVER — Finalize and publish
→ Legal review sign-off
→ Technical review (links, formatting, accessibility)
→ Translation QA (if multilingual)
→ Publication with version control
→ Set review trigger calendarWorkflow 2: Notice Update
Step 1: Identify trigger (new processing, regulation change, annual review)
Step 2: Run compliance checker on current notice
Step 3: Identify gaps and required updates
Step 4: Draft updated sections
Step 5: Re-verify with compliance checker
Step 6: Notify data subjects of material changes
Step 7: Update version date and change logWorkflow 3: Multi-Jurisdiction Notice
Step 1: Generate base notice for primary jurisdiction
→ python scripts/privacy_notice_scaffolder.py --jurisdiction [primary] ...
Step 2: Check jurisdiction requirements for additional territories
→ See references/jurisdiction_requirements.md
Step 3: Add jurisdiction-specific supplements
→ DE: TDDDG telecom disclosures, DSK guidance
→ FR: CNIL cookie requirements, LIL specifics
→ UK: ICO guidance, UK transfer mechanisms
Step 4: Verify each jurisdiction version
→ python scripts/notice_compliance_checker.py notice_de.md --jurisdiction DE
→ python scripts/notice_compliance_checker.py notice_fr.md --jurisdiction FR
Step 5: Publish with language/jurisdiction switcher---
Troubleshooting
| Problem | Possible Cause | Resolution |
|---|---|---|
| Low compliance score despite complete notice | Missing jurisdiction-specific requirements (e.g., DE Widerspruchsrecht prominence) | Run checker with --jurisdiction flag; review jurisdiction_requirements.md for local additions |
| Scaffolder generates too many sections | Combined notice type includes all audience sections | Use specific notice type instead of combined; or remove irrelevant sections post-generation |
| Art. 14 findings for direct collection | Checker flags Art. 14 requirements for B2B notice type | Correct — B2B often involves indirect collection; ensure source disclosure is included |
| Placeholder text in final notice | Template not fully populated | Search for [PLACEHOLDER] and {{variable}} markers; all must be replaced before publication |
| Cookie section missing from employee notice | Employee notice type does not include cookies by default | Add --has-cookies flag if employee-facing systems use cookies/tracking |
| AI section not generated | Missing --has-ai flag | Re-run scaffolder with --has-ai; review AI Act Art. 50 transparency requirements |
---
Success Criteria
- 100% Art. 13/14 compliance score — all mandatory disclosure elements present; zero missing items
- Jurisdiction-specific requirements met — compliance checker confirms local SA requirements addressed
- Type-specific requirements met — notice covers all audience-specific data processing activities
- No placeholder text remaining — all template variables replaced with actual information
- Writing style guide followed — "you/your" voice; short sentences; tables for complex information; precise legal citations
- Legal review completed — qualified privacy counsel sign-off on final notice
- Publication requirements met — accessible, versioned, dated, with change notification mechanism
---
Scope & Limitations
In Scope:
- Privacy notice skeleton generation for 6 notice types across 9 jurisdictions
- Compliance checking against Art. 13/14 GDPR mandatory disclosures
- Jurisdiction-specific requirement validation (DE, FR, AT, IT, ES, NL, BE, IE, UK)
- Notice type-specific section generation and validation
- AI Act Art. 50 transparency disclosure sections
- Cookie and tracking technology disclosure sections
- Writing style and plain language guidance
Out of Scope:
- Legal advice on specific legal basis selection — consult qualified privacy counsel
- Translation services — tool generates English templates; professional translation required
- Cookie consent implementation or CMP configuration
- DPIA generation (see
dpia-assessmentskill) - Privacy notice hosting or publication infrastructure
- Non-GDPR privacy notice formats (CCPA notice at collection, LGPD notices)
- Sector-specific notices (healthcare, financial services, children's services)
---
Anti-Patterns
| Anti-Pattern | Why It Fails | Better Approach |
|---|---|---|
| Copy-paste from another company | Different processing activities, jurisdictions, and legal bases; exposes liability gaps | Generate skeleton from actual parameters; fill with organization-specific information |
| One notice for all jurisdictions | Misses jurisdiction-specific requirements (DE TDDDG, FR CNIL, UK ICO); SA enforcement | Generate jurisdiction-specific versions or supplements using scaffolder per jurisdiction |
| Generic legal bases ("we process your data based on applicable law") | Art. 13(1)(c) requires specific legal basis per purpose; generic statement is non-compliant | Map each processing purpose to specific Art. 6(1) basis; document in purpose-basis table |
| Set and forget | Processing activities change; regulations evolve; notices become inaccurate | Set review triggers (see compliance_verification.md); run compliance checker quarterly |
| Overly legalistic language | Recital 58 requires clear and plain language; complex legal jargon is non-compliant | Follow writing style guide: "you/your" voice, short sentences, tables, examples |
---
Tool Reference
privacy_notice_scaffolder.py
Generates a privacy notice skeleton based on notice type, jurisdiction, and processing parameters.
| Flag | Required | Description |
|---|---|---|
--notice-type <type> | Yes | Notice type: website, applicant, employee, b2b, b2c, combined |
--jurisdiction <code> | Yes | Jurisdiction: DE, FR, AT, IT, ES, NL, BE, IE, UK |
--data-categories <list> | Yes | Comma-separated: personal, contact, usage, cookies, financial, health, employment, marketing, biometric |
--legal-bases <list> | Yes | Comma-separated: consent, contract, legal_obligation, legitimate_interests, vital_interests, public_task |
--has-cookies | No | Include cookies and tracking section |
--has-ai | No | Include AI and automated processing section |
--has-international-transfers | No | Include international transfers section |
--json | No | Output in JSON format |
notice_compliance_checker.py
Validates a privacy notice against Art. 13/14 GDPR requirements.
| Flag | Required | Description |
|---|---|---|
<notice_file> | Yes | Path to privacy notice file (markdown or text) |
--jurisdiction <code> | No | Jurisdiction for local requirements: DE, FR, AT, IT, ES, NL, BE, IE, UK |
--notice-type <type> | No | Notice type for type-specific checks: website, applicant, employee, b2b, b2c, combined |
--json | No | Output in JSON format |
Privacy Notice Compliance Verification
5-layer compliance verification system with post-generation checklists and writing style guide.
---
Table of Contents
- 5-Layer Verification System
- Layer 1: Jurisdiction-Specific Requirements
- Layer 2: Art. 13/14 Mandatory Disclosures
- Layer 3: General Checks
- Layer 4: Type-Specific Checks
- Layer 5: AI Act Compliance
- Post-Generation Checklist
- Writing Style Guide
- Common Compliance Failures
---
5-Layer Verification System
Layer 1: Jurisdiction-Specific Requirements
Run jurisdiction check first — these are the most commonly missed items.
| Jurisdiction | Check | Requirement | Pass Criteria |
|---|---|---|---|
| DE | Widerspruchsrecht | Art. 21 DSGVO right to object displayed separately and prominently | Separate heading/section; bold text; not buried in general rights list |
| DE | TDDDG reference | TDDDG §25 referenced for cookie/telemedia consent | TDDDG cited alongside GDPR for website/app notices |
| DE | BDSG §26 | Employee data processing basis cited | §26 BDSG referenced in employee/applicant notices |
| DE | DPO §38 BDSG | DPO appointment disclosure if 20+ employees | DPO section present with contact details |
| FR | CNIL compliance | CNIL cookie consent guidance followed | No "continue browsing" consent; equal reject/accept prominence |
| FR | LIL reference | Loi Informatique et Libertés cited where applicable | LIL referenced for supplementary provisions |
| FR | LCEN mentions | Legal mentions (publisher, hosting) | Mentions légales present or linked |
| AT | DSB reference | DSB as supervisory authority | DSB contact details in complaint section |
| AT | Works council | Works council (Betriebsrat) reference in employee notices | Works council notification for IT systems |
| IT | Garante reference | Garante as supervisory authority | Garante contact details |
| IT | Marketing granularity | Separate consent for marketing, profiling, third-party sharing | Granular consent mechanism described |
| ES | LOPDGDD reference | LOPDGDD cited alongside GDPR | LOPDGDD referenced |
| ES | Digital rights | Digital disconnection right in employee notices | Art. 88 LOPDGDD referenced |
| NL | Cookie wall prohibition | No cookie wall practice | Clear statement that access not conditional on cookie consent |
| BE | Bilingual notice | French/Dutch versions for Brussels; appropriate language per region | Language versions available or noted |
| IE | DPC reference | DPC as supervisory authority | DPC contact details |
| UK | UK GDPR citation | "UK GDPR" not "GDPR" for UK processing | UK GDPR and DPA 2018 cited |
| UK | PECR reference | PECR referenced for cookies/marketing | PECR cited in cookie and marketing sections |
| UK | ICO registration | ICO registration number if applicable | Registration number or reference included |
---
Layer 2: Art. 13/14 Mandatory Disclosures
Every privacy notice must include these elements. Missing any item is a compliance failure.
| # | Element | GDPR Article | Required Content | Common Gaps |
|---|---|---|---|---|
| 1 | Controller identity | Art. 13(1)(a) | Full legal name, registered address, contact details | Using brand name only; missing registration number |
| 2 | DPO contact | Art. 13(1)(b) | Name or title, email, postal address | Missing when DPO appointed; no dedicated contact |
| 3 | Purposes of processing | Art. 13(1)(c) | Specific purpose for each processing activity | Vague purposes ("improve services"); bundled purposes |
| 4 | Legal basis per purpose | Art. 13(1)(c) | Specific Art. 6(1) basis for each purpose | Generic "applicable law"; missing basis for some purposes |
| 5 | Legitimate interests | Art. 13(1)(d) | Specific interests pursued (if LI basis used) | "Our legitimate interests" without specification |
| 6 | Recipients | Art. 13(1)(e) | Named recipients or specific categories | "Third parties" without categorization |
| 7 | Transfer info | Art. 13(1)(f) | Countries, mechanisms (adequacy/SCCs/BCRs) | Missing transfer mechanism; generic "secure transfer" |
| 8 | Retention periods | Art. 13(2)(a) | Specific period or criteria for each category | "As long as necessary"; no per-category periods |
| 9 | Right to access | Art. 13(2)(b) | Right exists; how to exercise | Missing exercise method |
| 10 | Right to rectification | Art. 13(2)(b) | Right exists; how to exercise | Listed but no exercise method |
| 11 | Right to erasure | Art. 13(2)(b) | Right exists; applicable restrictions | No mention of restrictions/exceptions |
| 12 | Right to restriction | Art. 13(2)(b) | Right exists; when applicable | Often omitted entirely |
| 13 | Right to object | Art. 13(2)(b) | Right exists; separate prominence | Buried in rights list; not prominent |
| 14 | Right to portability | Art. 13(2)(b) | Right exists; format information | Missing format specification |
| 15 | Consent withdrawal | Art. 13(2)(c) | How to withdraw; not affecting prior processing | Missing withdrawal method; missing "prior processing" language |
| 16 | SA complaint right | Art. 13(2)(d) | SA name and contact details | Generic "supervisory authority"; missing contact |
| 17 | Automated decisions | Art. 13(2)(f) | Existence, logic, significance, consequences | Missing "meaningful information about logic"; missing consequences |
Art. 14 Additional Requirements (indirect collection):
| # | Element | Art. 14 Reference | Required Content |
|---|---|---|---|
| 18 | Source of data | Art. 14(2)(f) | Named source or category; whether publicly available |
| 19 | Categories obtained | Art. 14(1)(d) | Categories of personal data obtained from source |
| 20 | Timing of notice | Art. 14(3) | Within reasonable period, max 1 month; at first communication |
---
Layer 3: General Checks
| # | Check | Pass Criteria | Severity |
|---|---|---|---|
| 1 | Art. 21 object right prominence | Separate heading or bold formatting; not just listed with other rights | High |
| 2 | DPO contact provided (if appointed) | Dedicated contact details (not general info@ email) | High |
| 3 | Cookie consent mechanism referenced | How to manage cookies; link to settings | High (website) |
| 4 | Transfer mechanism specified | Adequacy decision, SCCs, BCRs — named, not generic | High |
| 5 | AI/automated processing disclosure | Art. 22 requirements met if applicable | High |
| 6 | Children's data handling | Age verification; parental consent if applicable | High |
| 7 | Special category dual basis | Both Art. 6 AND Art. 9 basis stated for special category data | High |
| 8 | No placeholder text remaining | Zero instances of [PLACEHOLDER], {{variable}}, [TBD], [INSERT] | Critical |
| 9 | Plain language | "You/your" voice; sentences under 25 words average; no unexplained legal terms | Medium |
| 10 | Consistent formatting | Uniform heading hierarchy; consistent table format | Medium |
| 11 | Version date present | "Last updated" or "Effective date" visible | Medium |
| 12 | Contact method specified | How to exercise rights (email, form, postal); response timeframe | High |
| 13 | Accessible format | Headings for navigation; adequate contrast; screen reader compatible | Medium |
| 14 | Change notification | How data subjects will be notified of material changes | Medium |
---
Layer 4: Type-Specific Checks
Applicant Notice
| # | Check | Requirement | Severity |
|---|---|---|---|
| 1 | §26 BDSG reference (DE) | Employment law basis cited for DE applicant data | High (DE) |
| 2 | Retention period specified | Default 6 months; AGG defense period | High |
| 3 | Talent pool consent separate | Not bundled with application submission | High |
| 4 | Background check basis | Legal basis specified if background checks performed | High |
| 5 | Diversity data handling | Voluntary basis; anonymization after use | Medium |
Employee Notice
| # | Check | Requirement | Severity |
|---|---|---|---|
| 1 | Works council notification | Reference to works council involvement (DE/AT) | High (DE/AT) |
| 2 | IT monitoring scope | What is monitored; purpose; access to results | High |
| 3 | BYOD policy | Scope of employer access; data segregation | Medium |
| 4 | Health data Art. 9 basis | Specific Art. 9(2) basis for health data | High |
| 5 | Performance data transparency | How performance data used; retention | Medium |
B2B Notice
| # | Check | Requirement | Severity |
|---|---|---|---|
| 1 | Art. 14 source disclosure | Source of data clearly identified | High |
| 2 | Categories obtained | What data obtained from each source | High |
| 3 | Notice timing | Within 1 month or at first communication | Medium |
| 4 | Publicly available indicator | Whether data from public sources | Medium |
B2C Notice
| # | Check | Requirement | Severity |
|---|---|---|---|
| 1 | Soft opt-in rules | Existing customer marketing basis explained | Medium |
| 2 | Payment processor disclosure | Payment processor identity and role | High |
| 3 | Loyalty program data | Purpose, profiling, retention if applicable | Medium |
| 4 | Marketing opt-out | Easy unsubscribe mechanism described | High |
---
Layer 5: AI Act Compliance
If the organization deploys AI systems, additional Art. 50 transparency requirements apply.
| # | Check | AI Act Reference | Requirement |
|---|---|---|---|
| 1 | AI system identification | Art. 50(1) | Individuals informed they are interacting with AI |
| 2 | AI system purpose | Art. 50(2) | Purpose of AI system disclosed |
| 3 | Emotion recognition | Art. 50(3) | Disclosure if emotion recognition or biometric categorization used |
| 4 | Deep fake / synthetic content | Art. 50(4) | Disclosure if content artificially generated or manipulated |
| 5 | High-risk AI | Art. 26(11) | Human oversight measures; right to explanation of AI-assisted decisions |
| 6 | GPAI output marking | Art. 50(2) | Machine-readable marking for AI-generated content |
---
Post-Generation Checklist
Legal Review (5 Items)
| # | Item | Reviewer | Sign-off |
|---|---|---|---|
| 1 | All legal bases correctly matched to purposes | Privacy counsel | ☐ |
| 2 | Retention periods comply with applicable law | Privacy counsel | ☐ |
| 3 | Transfer mechanisms correctly identified and implemented | Privacy counsel | ☐ |
| 4 | Exemptions and restrictions accurately stated | Privacy counsel | ☐ |
| 5 | Jurisdiction-specific requirements addressed | Local counsel | ☐ |
Technical Review (4 Items)
| # | Item | Reviewer | Sign-off |
|---|---|---|---|
| 1 | All links functional and correct | Web developer | ☐ |
| 2 | Cookie categories match CMP configuration | Web developer | ☐ |
| 3 | Rights exercise mechanism operational | Product team | ☐ |
| 4 | Privacy notice accessible from all relevant touchpoints | QA team | ☐ |
Translation QA (5 Items)
| # | Item | Reviewer | Sign-off |
|---|---|---|---|
| 1 | Legal terms correctly translated (not just literal) | Legal translator | ☐ |
| 2 | Jurisdiction-specific legal references maintained | Legal translator | ☐ |
| 3 | SA name and contact in local language | Legal translator | ☐ |
| 4 | Consistent terminology across notice | Legal translator | ☐ |
| 5 | Cultural appropriateness of examples and tone | Local reviewer | ☐ |
Publication Requirements (5 Items)
| # | Item | Details | Sign-off |
|---|---|---|---|
| 1 | Version number and date visible | "Version X.X — Last updated DD Month YYYY" | ☐ |
| 2 | Change log maintained | What changed, when, why | ☐ |
| 3 | Previous versions archived | Accessible for accountability | ☐ |
| 4 | Notification mechanism | How data subjects informed of material changes | ☐ |
| 5 | Prominent placement | Footer link, registration flow, first-use screen | ☐ |
Ongoing Review Triggers (6 Items)
| # | Trigger | Action | Timeline |
|---|---|---|---|
| 1 | New processing activity | Review and update affected sections | Before processing begins |
| 2 | New jurisdiction | Add jurisdiction-specific supplement | Before targeting new jurisdiction |
| 3 | Regulatory change | Review against new requirements | Within 30 days of change |
| 4 | SA guidance publication | Review against guidance | Within 30 days |
| 5 | Annual review | Full compliance check | Every 12 months |
| 6 | Data breach | Review notice accuracy post-incident | Within 7 days |
---
Writing Style Guide
Voice and Tone
| Principle | Guideline | Example |
|---|---|---|
| Address directly | Use "you" and "your data" | "We process your personal data..." not "The data subject's data is processed..." |
| Active voice | Controller as actor | "We collect your email address" not "Your email address is collected" |
| Plain language | No unexplained legal jargon | "We delete your data after 2 years" not "Data is subject to erasure upon expiry of the retention period" |
| Precise citations | Cite specific articles | "Under Art. 15 GDPR, you have the right..." not "Under applicable law..." |
| Short sentences | Average under 25 words | Split long legal sentences into digestible parts |
| Concrete periods | Specific retention | "We keep your data for 6 months" not "We keep your data as long as necessary" |
Formatting Guidelines
| Element | Recommendation |
|---|---|
| Tables | Use for purposes/legal bases mapping; retention periods; recipient lists; rights overview |
| Headings | Clear hierarchy (H1 title, H2 major sections, H3 subsections); descriptive not numbered |
| Bold | Key rights, important deadlines, controller name |
| Lists | For enumerated rights, data categories, processing purposes |
| Links | SA website, rights exercise form, cookie settings, related policies |
| Callouts | Jurisdiction-specific notes; special category warnings; AI processing flags |
Language Level
| Jurisdiction | Recommended Level | Notes |
|---|---|---|
| NL | B1 (AP guidance) | AP explicitly recommends B1 language level |
| All others | Plain language (Recital 58) | Clear and plain language; avoid legalese; explain technical terms |
| Children | Age-appropriate | Simple vocabulary; visual aids; shorter sentences |
Terms to Avoid
| Avoid | Use Instead |
|---|---|
| "Data subject" | "You" |
| "Processing" (alone) | "Use", "collect", "store", "share" (be specific) |
| "Legitimate interests" (unexplained) | "Our legitimate interest in [specific interest], such as [example]" |
| "Third parties" (unnamed) | Name categories: "our IT service providers", "payment processors" |
| "As long as necessary" | Specific period: "for 2 years after your last purchase" |
| "Applicable law" | Specific law: "Art. 6(1)(c) GDPR" or "§147 AO (German Tax Code)" |
---
Common Compliance Failures
| Rank | Failure | Frequency | Impact | Fix |
|---|---|---|---|---|
| 1 | Missing specific legal basis per purpose | Very common | High — SA enforcement priority | Map each purpose to Art. 6(1) basis in table format |
| 2 | Generic retention periods | Very common | High — fails Art. 13(2)(a) | Define per-category retention with legal basis |
| 3 | No Art. 21 prominence | Common | Medium — DE/AT enforcement | Separate section with bold formatting |
| 4 | Missing transfer mechanism | Common | High — Schrems II enforcement | Name mechanism (adequacy/SCCs) per transfer |
| 5 | Incomplete rights list | Occasional | Medium | Include all 8 rights with exercise method |
| 6 | No DPO contact despite appointment | Occasional | Medium | Dedicated DPO section with email and address |
| 7 | Placeholder text in published notice | Rare but critical | Critical | Search and replace all placeholders before publishing |
| 8 | Missing Art. 14 source for indirect collection | Common (B2B) | High | Source disclosure with public availability indicator |
| 9 | Missing AI/automated decision disclosure | Increasing | High — AI Act enforcement | Add Art. 22 section; Art. 50 AI Act if applicable |
| 10 | Cookie notice non-compliant | Very common | Medium — active enforcement | Granular consent; no pre-ticked; equal reject/accept |
Jurisdiction-Specific Privacy Notice Requirements
Privacy notice requirements beyond the GDPR baseline for 9 EU/EEA and UK jurisdictions.
---
Table of Contents
- Germany (DE)
- France (FR)
- Austria (AT)
- Italy (IT)
- Spain (ES)
- Netherlands (NL)
- Belgium (BE)
- Ireland (IE)
- United Kingdom (UK)
- Cross-Jurisdiction Comparison
---
Germany (DE)
Supervisory Authority
| Field | Details |
|---|---|
| Federal authority | BfDI (Bundesbeauftragter für den Datenschutz und die Informationsfreiheit) |
| State authorities | 16 Landesbeauftragte für den Datenschutz (one per Bundesland) |
| Website | https://www.bfdi.bund.de |
| Competence | BfDI for federal bodies and telecoms; state authorities for private sector and state bodies |
Requirements Beyond GDPR Baseline
| Requirement | Legal Basis | Details |
|---|---|---|
| Widerspruchsrecht prominence | Art. 21 DSGVO, DSK guidance | Right to object must be displayed separately and prominently — not buried in rights list. DSK recommends distinct section with bold formatting. |
| BDSG §26 employee data | BDSG §26 | Employee and applicant data processing requires specific legal basis under §26 BDSG (necessity for employment relationship). Must be cited alongside Art. 6 GDPR. |
| BDSG §38 DPO threshold | BDSG §38 | DPO mandatory if 20+ employees regularly engaged in automated processing of personal data. Lower threshold than GDPR Art. 37. |
| TDDDG (formerly TTDSG) | TDDDG §25 | Applies to telecom and telemedia services. Cookie consent requirements under §25 TDDDG (implements ePrivacy Art. 5(3)). Must reference TDDDG alongside GDPR for website notices. |
| DSK cookie guidance | DSK Orientierungshilfe | DSK (conference of German data protection authorities) guidance on cookie consent: no pre-ticked boxes, no cookie walls, granular category consent, documented consent proof. |
| Video surveillance | BDSG §4 | Specific disclosure requirements for CCTV: signage with controller identity, purpose, and contact details. §4 BDSG supplements GDPR Art. 13. |
| Credit scoring | BDSG §31 | If processing personal data for scoring, must reference §31 BDSG. Requirement for explainable scoring logic. |
Standard Wording Recommendations
- Reference "DSGVO" alongside "GDPR" in German-language notices
- Cite "BDSG" where applicable (employee data, DPO, video surveillance)
- Art. 21 section should use the standard DSK-recommended formulation
- Include both "Widerspruchsrecht" (right to object) and "Widerrufsrecht" (right to withdraw consent) clearly distinguished
Retention Guidance
| Category | German Standard | Legal Basis |
|---|---|---|
| Tax records | 10 years | §147 AO (Abgabenordnung) |
| Commercial records | 6 years | §257 HGB (Handelsgesetzbuch) |
| Employee payroll | 10 years | §147 AO |
| Applicant data | 6 months (AGG defense) | AGG (Allgemeines Gleichbehandlungsgesetz) |
| CCTV footage | Max 72 hours (standard) | BDSG §4, DSK guidance |
| Contractual data | 3 years after contract end | §195 BGB (limitation period) |
---
France (FR)
Supervisory Authority
| Field | Details |
|---|---|
| Authority | CNIL (Commission Nationale de l'Informatique et des Libertés) |
| Website | https://www.cnil.fr |
| Language | French required for notices targeting French individuals |
Requirements Beyond GDPR Baseline
| Requirement | Legal Basis | Details |
|---|---|---|
| CNIL cookie recommendations | CNIL Délibération 2020-091 | Specific cookie consent requirements: "Continue browsing" is not valid consent; accept and refuse must be equally prominent; consent must be recordable with proof; cookie wall prohibition. |
| LIL specifics | Loi n° 78-17 (Loi Informatique et Libertés) | LIL supplements GDPR with French-specific provisions for health research, genetic data, and public sector processing. Must reference LIL where applicable. |
| LCEN hosting | Loi n° 2004-575 (LCEN) | Website operators must identify: publisher (editor), hosting provider, and provide legal mentions (mentions légales). Distinct from privacy notice but often combined. |
| Health data processing | LIL Chapter IX | Enhanced requirements for health data processing: specific CNIL authorization requirements; reference data hosting certification (HDS — Hébergeur de Données de Santé). |
| Minor consent age | LIL Art. 45 | Consent age set at 15 years (lower than GDPR default of 16). Parental consent required for processing children's data below 15. |
| Marketing consent | CNIL guidance | B2C electronic marketing requires prior opt-in consent (except soft opt-in for existing customers under Art. L34-5 CPCE). B2B professional email may use legitimate interests. |
Standard Wording Recommendations
- Use "RGPD" alongside "GDPR" in French-language notices
- Reference "Loi Informatique et Libertés" where supplementary provisions apply
- Include CNIL complaint procedure with specific CNIL contact details
- Mentions légales (legal notices) can be separate page but should cross-reference privacy notice
Retention Guidance
| Category | French Standard | Legal Basis |
|---|---|---|
| Accounting records | 10 years | Code de Commerce Art. L123-22 |
| Tax documents | 6 years | Livre des Procédures Fiscales Art. L102 B |
| Contractual data | 5 years after contract end | Code Civil Art. 2224 (limitation period) |
| Applicant data | 2 years maximum (CNIL recommendation) | CNIL recommendation |
| Customer prospect data | 3 years from last contact (CNIL recommendation) | CNIL Délibération |
| Cookie consent proof | 13 months maximum | CNIL recommendation |
---
Austria (AT)
Supervisory Authority
| Field | Details |
|---|---|
| Authority | DSB (Datenschutzbehörde) |
| Website | https://www.dsb.gv.at |
Requirements Beyond GDPR Baseline
| Requirement | Legal Basis | Details |
|---|---|---|
| DSG amendments | Datenschutzgesetz (DSG) | Austrian DSG supplements GDPR; includes specific provisions for research, archiving, and media processing exemptions. |
| Works council (Betriebsrat) | ArbVG (Arbeitsverfassungsgesetz) | Employee data processing systems require works council agreement (similar to DE). §96a ArbVG for systems affecting human dignity. |
| Video surveillance | DSG §12-13 | Specific provisions for image processing: registration requirement removed but documentation required; retention max 72 hours standard. |
| Minor consent age | DSG §4(4) | Consent age set at 14 years (lower than GDPR default). |
Retention Guidance
| Category | Austrian Standard | Legal Basis |
|---|---|---|
| Tax/accounting records | 7 years | BAO §132 (Bundesabgabenordnung) |
| Commercial records | 7 years | UGB §212 (Unternehmensgesetzbuch) |
| Employee records | 3 years after employment end | General limitation period |
| CCTV footage | Max 72 hours | DSB guidance |
---
Italy (IT)
Supervisory Authority
| Field | Details |
|---|---|
| Authority | Garante per la protezione dei dati personali |
| Website | https://www.garanteprivacy.it |
Requirements Beyond GDPR Baseline
| Requirement | Legal Basis | Details |
|---|---|---|
| Garante simplified notice | Garante guidelines | Garante has issued guidelines for simplified privacy notices: layered approach recommended; first layer with essential information; full notice accessible via link. |
| Cookie guidelines | Garante Provvedimento 10 June 2021 | Specific cookie consent requirements: scrolling is not consent; analytics cookies may use legitimate interests only with IP anonymization; third-party cookies require consent. |
| Marketing consent granularity | Garante guidelines | Marketing consent must be granular: separate consent for (1) general marketing, (2) profiling, (3) third-party sharing. Bundled consent invalid. |
| Simplified notice for minors | Garante guidelines | Notices directed at minors must use age-appropriate language; visual aids recommended; consent age 14 (Codice Privacy Art. 2-quinquies). |
| Video surveillance | Garante Provvedimento 2010 | Specific requirements: signage model provided by Garante; retention generally 24-48 hours; maximum 7 days unless justified. |
Retention Guidance
| Category | Italian Standard | Legal Basis |
|---|---|---|
| Tax records | 10 years | Art. 2220 Codice Civile |
| Commercial records | 10 years | Art. 2220 Codice Civile |
| Employee records | 5 years after employment end | Limitation period |
| Marketing contacts | Garante: 24 months for marketing, 12 months for profiling | Garante guidelines |
---
Spain (ES)
Supervisory Authority
| Field | Details |
|---|---|
| National authority | AEPD (Agencia Española de Protección de Datos) |
| Regional authorities | APDCAT (Catalonia), AVPD (Basque Country), CPDPA (Andalusia) |
| Website | https://www.aepd.es |
Requirements Beyond GDPR Baseline
| Requirement | Legal Basis | Details |
|---|---|---|
| LOPDGDD digital rights | Title X LOPDGDD | Digital disconnection right for employees (Art. 88); right to privacy in use of digital devices at work (Art. 87); right to digital education (Art. 83). |
| Deceased persons' data | Art. 3 LOPDGDD | Heirs and authorized persons can exercise rights on behalf of deceased data subjects. Notice should reference this right. |
| AEPD guidance on layered notices | AEPD guide on transparency | AEPD promotes layered notice approach: first layer with essential info at collection point; second layer with complete information. |
| Employee monitoring | Art. 87-91 LOPDGDD | Specific provisions for employee digital monitoring: must inform employees; union notification; proportionality principle. |
| DPO extended requirement | Art. 34 LOPDGDD | DPO mandatory for additional categories: healthcare entities, education institutions, telecoms, financial entities, insurance, energy, and others beyond GDPR Art. 37. |
Retention Guidance
| Category | Spanish Standard | Legal Basis |
|---|---|---|
| Tax records | 4 years | Ley General Tributaria |
| Commercial records | 6 years | Código de Comercio Art. 30 |
| Employee records | 4 years after employment end | Limitation period |
| Contractual data | 5 years | Art. 1964 Código Civil |
---
Netherlands (NL)
Supervisory Authority
| Field | Details |
|---|---|
| Authority | AP (Autoriteit Persoonsgegevens) |
| Website | https://www.autoriteitpersoonsgegevens.nl |
Requirements Beyond GDPR Baseline
| Requirement | Legal Basis | Details |
|---|---|---|
| Cookie wall prohibition | AP enforcement policy | Cookie walls (denying access unless cookies accepted) are prohibited. Users must be able to access service without accepting non-essential cookies. Active AP enforcement. |
| BSN processing | UAVG Art. 46 | BSN (Burgerservicenummer / citizen service number) processing only permitted when legally required. Must not use BSN as general identifier. |
| AP transparency guidance | AP guidelines | AP emphasizes: plain language (B1 language level for consumer notices); avoid legal jargon; use examples; test readability. |
| Healthcare data | UAVG Art. 30 | Additional safeguards for health data processing; reference to Wet op de geneeskundige behandelingsovereenkomst (WGBO) for patient data. |
Retention Guidance
| Category | Dutch Standard | Legal Basis |
|---|---|---|
| Tax records | 7 years | AWR (Algemene wet inzake rijksbelastingen) |
| Employee records | 2 years after employment end (5 years for payroll) | Wet bewaring personeelsgegevens; fiscal retention |
| Medical records | 20 years | WGBO Art. 454 |
| Contractual data | 5 years | Art. 3:307 BW (limitation period) |
---
Belgium (BE)
Supervisory Authority
| Field | Details |
|---|---|
| Authority | APD/GBA (Autorité de protection des données / Gegevensbeschermingsautoriteit) |
| Website | https://www.gegevensbeschermingsautoriteit.be |
| Languages | French and Dutch (bilingual country) |
Requirements Beyond GDPR Baseline
| Requirement | Legal Basis | Details |
|---|---|---|
| Bilingual requirements | Belgian Data Protection Act | Notices in bilingual regions (Brussels) should be available in both French and Dutch. Flemish Region: Dutch. Walloon Region: French. |
| Direct marketing | APD guidance | APD has specific guidance on direct marketing consent; distinction between B2C (consent required) and B2B (legitimate interests may apply). |
| Employee monitoring | CBA No. 81 | Collective Bargaining Agreement No. 81 governs employee internet/email monitoring; must inform employees via works council. |
Retention Guidance
| Category | Belgian Standard | Legal Basis |
|---|---|---|
| Tax records | 7 years | Code des impôts sur les revenus |
| Commercial records | 7 years | Code de droit économique |
| Employee records | 5 years after employment end | Social security requirements |
| Contractual data | 10 years | Art. 2262bis Code Civil |
---
Ireland (IE)
Supervisory Authority
| Field | Details |
|---|---|
| Authority | DPC (Data Protection Commission) |
| Website | https://www.dataprotection.ie |
| Significance | Lead supervisory authority for many US tech companies (Google, Meta, Apple, Microsoft) under one-stop-shop mechanism |
Requirements Beyond GDPR Baseline
| Requirement | Legal Basis | Details |
|---|---|---|
| DPC guidance on transparency | DPC guidance notes | DPC emphasizes: notices must be concise; avoid "information fatigue"; layered approach recommended; digital-first design. |
| Cross-border processing | GDPR Art. 56 / Irish DPA 2018 | If processing involves cross-border elements, DPC may be lead SA. Notice should reference DPC as complaint authority for cross-border cases. |
| Employee data | DPC guidance | DPC has issued specific guidance on employee monitoring, CCTV in workplaces, and biometric data processing in employment context. |
| Children's data | DPC Fundamentals for a Child-Oriented Approach | DPC guidance on children's data: age-appropriate language; parental controls; privacy by design for children's services. Consent age: 16 in Ireland (no reduction from GDPR default). |
Retention Guidance
| Category | Irish Standard | Legal Basis |
|---|---|---|
| Tax records | 6 years | Taxes Consolidation Act 1997 |
| Company records | 6 years | Companies Act 2014 |
| Employee records | 3 years after employment end | Organisation of Working Time Act |
| Contractual data | 6 years | Statute of Limitations 1957 |
---
United Kingdom (UK)
Supervisory Authority
| Field | Details |
|---|---|
| Authority | ICO (Information Commissioner's Office) |
| Website | https://ico.org.uk |
| Registration | Data protection fee required (annual) |
Requirements Beyond GDPR Baseline
| Requirement | Legal Basis | Details |
|---|---|---|
| UK GDPR references | UK GDPR (retained EU law) | Post-Brexit: cite "UK GDPR" not "GDPR" for UK processing. UK GDPR is substantively identical but legally distinct. Data Protection Act 2018 supplements UK GDPR. |
| ICO privacy notice guidance | ICO Code of Practice | ICO provides detailed guidance on privacy notice content, format, and delivery. Layered notices recommended. Plain English emphasis. |
| UK transfer mechanisms | UK GDPR Chapter V | UK International Data Transfer Agreement (IDTA) or UK Addendum to EU SCCs. UK adequacy decisions (separate from EU). UK-US Data Bridge (extension of DPF). |
| PECR for cookies and marketing | PECR SI 2003/2426 | Privacy and Electronic Communications Regulations: cookie consent requirements; direct marketing rules; soft opt-in for existing customers (Regulation 22). |
| ICO registration | DPA 2018 s.137 | Most organizations processing personal data must register with ICO and pay annual data protection fee. Registration number should be included in notice. |
| Age-appropriate design | Children's Code (ICO) | If services accessed by children: 15 standards including privacy by default; data protection impact assessments; age-appropriate privacy information. |
Standard Wording Recommendations
- Reference "UK GDPR" and "Data Protection Act 2018" (not EU GDPR)
- Include ICO contact details with complaint procedure
- Reference PECR for cookie sections
- Include ICO registration number if applicable
- For transfers: reference UK IDTA or UK Addendum, not EU SCCs alone
Retention Guidance
| Category | UK Standard | Legal Basis |
|---|---|---|
| Tax records | 6 years (7 for CT) | Finance Act; HMRC requirements |
| Company records | 6 years | Companies Act 2006 |
| Employee records | 6 years after employment end | Limitation Act 1980 |
| Contractual data | 6 years | Limitation Act 1980 |
| CCTV footage | 30 days (standard) | ICO guidance |
| Marketing consent | Duration of consent + 12 months | ICO guidance |
---
Cross-Jurisdiction Comparison
Key Differences Summary
| Element | DE | FR | AT | IT | ES | NL | BE | IE | UK |
|---|---|---|---|---|---|---|---|---|---|
| Consent age | 16 | 15 | 14 | 14 | 14 | 16 | 13 | 16 | 13 |
| DPO threshold (beyond Art. 37) | 20 employees (§38 BDSG) | No | No | No | Extended list (Art. 34 LOPDGDD) | No | No | No | No |
| Cookie wall allowed | No | No | No | No | No | No | No | No | No |
| Soft opt-in | Yes (§7(3) UWG) | Yes (CPCE) | Yes | Yes | Yes | Yes | Yes | Yes | Yes (PECR Reg. 22) |
| Works council co-determination | Yes | Yes (CSE) | Yes (BR) | Yes (RSU) | Yes (CE) | Yes (OR) | Yes (CE/OR) | Limited | Limited |
| Video surveillance specific law | Yes (§4 BDSG) | Yes (CNIL) | Yes (§12-13 DSG) | Yes (Garante) | Yes (LOPDGDD) | Yes (AP) | Yes (CBA) | Yes (DPC) | Yes (ICO) |
| Tax retention (years) | 10 | 6-10 | 7 | 10 | 4 | 7 | 7 | 6 | 6-7 |
| General limitation period | 3 years | 5 years | 3 years | 5 years | 5 years | 5 years | 10 years | 6 years | 6 years |
Privacy Notice Types Guide
Detailed guidance for 6 privacy notice types with audience-specific requirements, data categories, and jurisdiction notes.
---
Table of Contents
- Website/App Notice
- Applicant/Recruiting Notice
- Employee Notice
- Business Partner (B2B) Notice
- B2C Customer Notice
- Combined Notice
---
Website/App Notice
Platform Sub-Types
| Sub-Type | Specific Sections Needed | Additional Considerations |
|---|---|---|
| Brochure website | Cookie notice, contact form data, analytics | Minimal processing; often consent + legitimate interests basis |
| E-commerce | Payment processing, order fulfillment, account data, marketing | Contract basis for orders; separate consent for marketing; payment processor disclosure |
| SaaS platform | Account data, usage data, API data, customer content | Processor/controller distinction for customer data; sub-processor list |
| Mobile app | Device data, location, push notifications, app analytics | Device permissions disclosure; SDK/third-party library data sharing; app store requirements |
| Marketplace | Seller data, buyer data, transaction data, reviews | Multiple data subject categories; dual-role processing (buyers and sellers) |
| AI platform | Training data, inference data, model outputs, user prompts | EU AI Act Art. 50 transparency; Art. 22 automated decisions; data retention for training |
Required Sections for Website/App
| Section | Required | Notes |
|---|---|---|
| Controller identity | Yes | Legal entity, not just brand name |
| DPO contact | Yes (if appointed) | Separate from general contact |
| Data categories collected | Yes | Include automatically collected data |
| Purposes and legal bases | Yes | Per-purpose legal basis mapping |
| Recipients | Yes | Analytics providers, CDN, hosting, payment |
| International transfers | Yes (if applicable) | Cloud providers often transfer data |
| Retention periods | Yes | Per-category; session vs. persistent cookies |
| Data subject rights | Yes | All 8 rights with exercise method |
| Cookies and tracking | Yes | Category table; consent mechanism reference |
| Third-party integrations | Recommended | Social media plugins, embedded content |
| Children's data | If applicable | Age verification; parental consent mechanisms |
Typical Data Categories
| Category | Examples | Legal Basis (Typical) |
|---|---|---|
| Identity | Name, email (registration) | Contract |
| Contact form | Name, email, message | Legitimate interests or consent |
| Usage data | Pages visited, session duration, clicks | Legitimate interests or consent |
| Device data | IP address, browser, OS, screen resolution | Legitimate interests |
| Cookies (necessary) | Session, CSRF, preferences | Legitimate interests (strictly necessary) |
| Cookies (analytics) | Google Analytics, Hotjar | Consent |
| Cookies (marketing) | Facebook Pixel, Google Ads | Consent |
| Payment data | Card details, billing address | Contract |
| Account data | Username, password hash, preferences | Contract |
---
Applicant/Recruiting Notice
Hiring-Specific Data Categories
| Category | Examples | Legal Basis | Retention |
|---|---|---|---|
| Application materials | CV, cover letter, portfolio | Pre-contractual measures (Art. 6(1)(b)) | 6 months post-decision (default) |
| Contact details | Email, phone, address | Pre-contractual measures | 6 months post-decision |
| Qualifications | Degrees, certifications, licenses | Pre-contractual measures | 6 months post-decision |
| Interview notes | Assessment records, panel feedback | Legitimate interests (Art. 6(1)(f)) | 6 months post-decision |
| Reference checks | Previous employer feedback | Consent (Art. 6(1)(a)) | 6 months post-decision |
| Background checks | Criminal record, credit check (if applicable) | Legal obligation or consent | 6 months post-decision |
| Right to work | Passport, visa, work permit | Legal obligation (Art. 6(1)(c)) | Duration of employment + statutory retention |
| Diversity data | Gender, ethnicity, disability (voluntary) | Consent; Art. 9(2)(b) employment law | Anonymized after use; aggregate statistics retained |
| Salary expectations | Current/expected compensation | Legitimate interests | 6 months post-decision |
Retention Defaults
| Scenario | Default Retention | Basis |
|---|---|---|
| Unsuccessful application | 6 months from decision | Defense of legal claims (discrimination, unfair hiring) |
| Talent pool (with consent) | 12 months (renewable) | Consent — must be freely given, not bundled with application |
| Successful application | Transfer to employee file | Contract basis |
| Withdrawn application | Delete within 30 days of withdrawal | No further basis for processing |
Talent Pool Consent Requirements
- Consent must be separate from application submission
- Must be freely given — refusal must not affect application
- Must specify retention period and review frequency
- Easy withdrawal mechanism (email or portal)
- Re-consent before expiry if extending retention
DE-Specific (§26 BDSG)
- Employee data processing (including applicants) governed by §26 BDSG
- Processing must be necessary for employment relationship decisions
- Works council (Betriebsrat) may have co-determination rights in hiring process
- Discriminatory questioning restrictions (AGG — Allgemeines Gleichbehandlungsgesetz)
---
Employee Notice
Employee-Specific Data Categories
| Category | Examples | Legal Basis | Special Handling |
|---|---|---|---|
| Employment contract data | Role, start date, salary, benefits | Contract (Art. 6(1)(b)) | — |
| Payroll data | Bank details, tax code, NI/social security | Legal obligation (Art. 6(1)(c)) | Financial data protection |
| Performance data | Reviews, objectives, development plans | Legitimate interests (Art. 6(1)(f)) | Transparency required |
| IT system data | Login records, email usage, internet usage | Legitimate interests | Works council agreement |
| Health data | Sick leave, occupational health, disability | Art. 9(2)(b) employment law | Special category — additional safeguards |
| CCTV footage | Workplace video surveillance | Legitimate interests (security) | Signage, retention limits, access restrictions |
| Location data | Company vehicle GPS, field worker tracking | Legitimate interests or consent | Proportionality assessment required |
| Biometric data | Access control fingerprint/face | Consent or employment law | Special category — DPIA recommended |
Works Council Notification (DE/AT)
| Topic | Works Council Involvement | Legal Basis |
|---|---|---|
| IT systems monitoring | Co-determination right (§87(1)(6) BetrVG) | Must agree before implementation |
| CCTV installation | Co-determination right | Must agree on scope, retention, access |
| Performance monitoring tools | Co-determination right | Must agree on metrics and use |
| Employee data processing agreements | Information right | Must be informed of DPA terms |
| BYOD policies | Co-determination right | Must agree on scope of employer access |
| HR information systems | Co-determination right | Must agree on data collected and access |
IT Monitoring Disclosure
| Monitoring Type | Disclosure Required | Key Points |
|---|---|---|
| Email monitoring | Yes — scope and purpose | Whether content or metadata only; personal use policy |
| Internet usage logging | Yes — scope and purpose | Categories logged; personal use allowance |
| Device management (MDM) | Yes — capabilities | What data employer can access/wipe; BYOD boundaries |
| Keylogger/screenshot | Highly restricted; requires strong justification | Generally disproportionate; exceptional circumstances only |
| DLP (Data Loss Prevention) | Yes — triggers and scope | What triggers alert; who reviews; false positive handling |
BYOD Policy Disclosure
- What data employer can access on personal device
- Remote wipe scope (company data only vs. full device)
- App installation requirements and restrictions
- Employee's right to refuse BYOD participation
- Data segregation measures (containerization)
---
Business Partner (B2B) Notice
Art. 14 Requirements (Indirect Collection)
When personal data is not collected directly from the data subject (common in B2B), Art. 14 GDPR applies:
| Requirement | Art. 14 Reference | B2B Context |
|---|---|---|
| Source of data | Art. 14(2)(f) | "We received your data from your employer" or "from public business registers" |
| Categories of data obtained | Art. 14(1)(d) | Name, business email, job title, business phone |
| Timing of notice | Art. 14(3) | Within reasonable period, max 1 month; or at first communication |
| Whether from publicly available source | Art. 14(2)(f) | LinkedIn, company websites, business directories |
Typical B2B Data Categories
| Category | Examples | Source | Legal Basis |
|---|---|---|---|
| Business contact details | Name, title, email, phone | Counterparty company, business cards | Legitimate interests (Art. 6(1)(f)) |
| Company information | Company name, address, registration | Public registers, company website | Legitimate interests |
| Transaction data | Orders, invoices, payment history | Business relationship | Contract (Art. 6(1)(b)) |
| Communication records | Emails, meeting notes, correspondence | Business relationship | Legitimate interests |
| Due diligence data | Credit checks, sanctions screening | Credit agencies, sanctions lists | Legal obligation or legitimate interests |
Source Disclosure Template
We obtained your business contact details from [source: your employer / public business register / industry event / your company website / your business card provided at [event]]. We process your data for the purpose of [managing our business relationship / contract performance / business development]. This notice is provided in accordance with Art. 14 GDPR.
---
B2C Customer Notice
Soft Opt-In Rules
The "soft opt-in" allows marketing to existing customers about similar products without prior consent, subject to conditions:
| Condition | Requirement |
|---|---|
| Existing customer | Data subject purchased or negotiated purchase of a product/service |
| Similar products/services | Marketing relates to similar products/services to those already purchased |
| Opt-out at collection | Clear opportunity to opt-out at point of data collection |
| Opt-out in every message | Easy unsubscribe mechanism in every marketing communication |
| No consent required | Soft opt-in replaces consent requirement for email marketing |
Jurisdiction notes:
- DE: §7(3) UWG implements soft opt-in; strictly limited to direct electronic marketing
- FR: Art. L34-5 CPCE implements soft opt-in; CNIL guidance applies
- UK: Regulation 22 PECR implements soft opt-in; ICO guidance
- IT: Garante guidance on soft opt-in scope and limitations
Payment Processor Disclosure
| Disclosure Element | Details |
|---|---|
| Processor identity | Name of payment processor (e.g., Stripe, Adyen, PayPal) |
| Data shared | Card details, billing address, transaction amount |
| Controller/processor role | Payment processor typically acts as independent controller for fraud prevention |
| PCI-DSS compliance | Note payment data handling meets PCI-DSS standards |
| Data location | Where payment data is processed and stored |
| Retention | Transaction records per tax/accounting legal obligation |
Loyalty Program Disclosure
| Element | Requirement |
|---|---|
| Purpose | Points accumulation, rewards, personalized offers |
| Data collected | Purchase history, preferences, engagement data |
| Legal basis | Consent (for profiling) or contract (for points calculation) |
| Profiling | If loyalty data used for profiling, Art. 22 disclosure required |
| Third-party sharing | Partners in loyalty network |
| Retention | Duration of membership + statutory period |
---
Combined Notice
When to Use Combined Notices
Use a combined notice when:
- Organization processes data of multiple audience types (customers + website visitors)
- Audiences overlap significantly
- Maintaining multiple notices creates inconsistency risk
Merge Strategies
| Strategy | Approach | Best For |
|---|---|---|
| Layered sections | Universal sections (controller, DPO, rights) + audience-specific sections clearly labeled | Organizations with 2-3 distinct audiences |
| Tabbed/accordion | Digital notice with expandable sections per audience | Web-based notices; good UX |
| Appendix model | Core notice + audience-specific appendices | Complex processing with many audiences |
| Unified with callouts | Single flowing notice with "If you are a [customer/employee/visitor]..." callouts | Simple processing, overlapping categories |
Combined Notice Structure
| Section | Universal | Audience-Specific Notes |
|---|---|---|
| Controller identity | Yes | — |
| DPO contact | Yes | — |
| Data categories | Partial | List all; mark which audiences each applies to |
| Purposes and legal bases | Partial | Some purposes universal; others audience-specific |
| Recipients | Partial | Some recipients universal (hosting); others audience-specific |
| International transfers | Yes | — |
| Retention periods | Audience-specific | Different retention per audience and purpose |
| Data subject rights | Yes | Exercise mechanism may differ per audience |
| Cookies | Website visitors only | Not applicable to employees/B2B |
| Employee-specific | Employees only | Works council, monitoring, BYOD |
| B2B source disclosure | B2B only | Art. 14 requirements |
Risks of Combined Notices
| Risk | Mitigation |
|---|---|
| Information overload | Use clear headings and audience markers; layered approach |
| Missing audience-specific requirements | Checklist per audience type before publishing |
| Confusion about which sections apply | "This section applies to you if..." intro per section |
| Maintenance burden | Version control; designated owner per audience section |
#!/usr/bin/env python3
"""
Privacy Notice Compliance Checker
Validates a privacy notice text against Art. 13/14 GDPR requirements.
Checks for mandatory disclosure elements, jurisdiction-specific requirements,
and notice type-specific sections. Outputs compliance score and findings.
Usage:
python notice_compliance_checker.py privacy_notice.md
python notice_compliance_checker.py privacy_notice.md --jurisdiction DE
python notice_compliance_checker.py privacy_notice.md --jurisdiction FR --notice-type website
python notice_compliance_checker.py privacy_notice.md --jurisdiction DE --notice-type employee --json
"""
import argparse
import json
import re
import sys
from datetime import datetime
from pathlib import Path
from typing import Dict, List, Optional, Tuple
# Art. 13 mandatory elements with search patterns
ART13_CHECKS: List[Dict] = [
{
"id": "controller_identity",
"name": "Controller identity and contact details",
"article": "Art. 13(1)(a)",
"patterns": [r"controller", r"who we are", r"responsible\s+(for|party)", r"data\s+controller",
r"operated\s+by", r"company\s+name", r"registered\s+(address|office)"],
"weight": 10,
"category": "mandatory",
},
{
"id": "dpo_contact",
"name": "Data Protection Officer contact details",
"article": "Art. 13(1)(b)",
"patterns": [r"data\s+protection\s+officer", r"\bDPO\b", r"dpo@", r"datenschutzbeauftragte"],
"weight": 8,
"category": "mandatory",
},
{
"id": "purposes",
"name": "Purposes of processing",
"article": "Art. 13(1)(c)",
"patterns": [r"purpose", r"why\s+we\s+(process|collect|use)", r"reason.*process",
r"we\s+(use|process|collect)\s+your\s+(personal\s+)?data"],
"weight": 10,
"category": "mandatory",
},
{
"id": "legal_bases",
"name": "Legal bases for processing",
"article": "Art. 13(1)(c)",
"patterns": [r"legal\s+basis", r"lawful\s+basis", r"Art\.?\s*6", r"legitimate\s+interest",
r"consent", r"contractual\s+necessity", r"legal\s+obligation"],
"weight": 10,
"category": "mandatory",
},
{
"id": "recipients",
"name": "Recipients or categories of recipients",
"article": "Art. 13(1)(e)",
"patterns": [r"recipient", r"who\s+receives", r"share.*data", r"disclose.*to",
r"third\s+part(y|ies)", r"service\s+provider", r"processor"],
"weight": 8,
"category": "mandatory",
},
{
"id": "transfers",
"name": "International transfers information",
"article": "Art. 13(1)(f)",
"patterns": [r"transfer", r"outside\s+(the\s+)?(EU|EEA)", r"third\s+countr",
r"international", r"adequacy", r"standard\s+contractual", r"SCC"],
"weight": 7,
"category": "mandatory",
},
{
"id": "retention",
"name": "Retention periods or criteria",
"article": "Art. 13(2)(a)",
"patterns": [r"retention", r"how\s+long", r"storage\s+period", r"keep.*data",
r"delet(e|ion)", r"retain", r"stored\s+for"],
"weight": 8,
"category": "mandatory",
},
{
"id": "right_access",
"name": "Right of access",
"article": "Art. 13(2)(b) / Art. 15",
"patterns": [r"right.*access", r"Art\.?\s*15", r"copy\s+of\s+your\s+data",
r"request.*access", r"obtain.*data"],
"weight": 5,
"category": "mandatory",
},
{
"id": "right_rectification",
"name": "Right to rectification",
"article": "Art. 13(2)(b) / Art. 16",
"patterns": [r"rectification", r"correction", r"Art\.?\s*16", r"correct.*data",
r"inaccurate"],
"weight": 5,
"category": "mandatory",
},
{
"id": "right_erasure",
"name": "Right to erasure",
"article": "Art. 13(2)(b) / Art. 17",
"patterns": [r"erasure", r"right\s+to\s+be\s+forgotten", r"Art\.?\s*17",
r"delet(e|ion)\s+of\s+your\s+data", r"request.*delet"],
"weight": 5,
"category": "mandatory",
},
{
"id": "right_restriction",
"name": "Right to restriction of processing",
"article": "Art. 13(2)(b) / Art. 18",
"patterns": [r"restriction", r"Art\.?\s*18", r"restrict.*process", r"limit.*process"],
"weight": 5,
"category": "mandatory",
},
{
"id": "right_portability",
"name": "Right to data portability",
"article": "Art. 13(2)(b) / Art. 20",
"patterns": [r"portability", r"Art\.?\s*20", r"machine.?readable",
r"structured.*format", r"transfer.*data.*to\s+another"],
"weight": 5,
"category": "mandatory",
},
{
"id": "right_objection",
"name": "Right to object",
"article": "Art. 13(2)(b) / Art. 21",
"patterns": [r"right\s+to\s+object", r"Art\.?\s*21", r"object\s+to\s+process",
r"Widerspruch"],
"weight": 5,
"category": "mandatory",
},
{
"id": "right_automated",
"name": "Automated decision-making disclosure",
"article": "Art. 13(2)(f) / Art. 22",
"patterns": [r"automated\s+decision", r"Art\.?\s*22", r"profiling",
r"automated\s+process.*legal", r"solely\s+automated"],
"weight": 6,
"category": "mandatory",
},
{
"id": "consent_withdrawal",
"name": "Right to withdraw consent",
"article": "Art. 13(2)(c) / Art. 7(3)",
"patterns": [r"withdraw.*consent", r"revoke.*consent", r"Art\.?\s*7\s*\(3\)",
r"withdrawal\s+does\s+not\s+affect"],
"weight": 6,
"category": "mandatory",
},
{
"id": "sa_complaint",
"name": "Right to complain to supervisory authority",
"article": "Art. 13(2)(d)",
"patterns": [r"supervisory\s+authority", r"complain", r"lodge\s+a\s+complaint",
r"Aufsichtsbeh", r"CNIL", r"ICO", r"DPC", r"Garante",
r"AEPD", r"Autoriteit", r"APD", r"DSB", r"BfDI"],
"weight": 7,
"category": "mandatory",
},
]
# General quality checks
GENERAL_CHECKS: List[Dict] = [
{
"id": "art21_prominence",
"name": "Art. 21 right to object is prominently displayed",
"patterns": [r"(###|##)\s*.*(object|Widerspruch)", r"\*\*.*right\s+to\s+object.*\*\*",
r"prominently", r"separately\s+(from|listed)"],
"weight": 4,
"category": "general",
},
{
"id": "no_placeholders",
"name": "No placeholder text remaining",
"patterns": [], # Special check - inverse
"weight": 5,
"category": "general",
},
{
"id": "plain_language",
"name": "Plain language indicators",
"patterns": [r"\byou\b", r"\byour\b", r"\byour\s+data\b", r"\byour\s+personal\b"],
"weight": 3,
"category": "general",
},
{
"id": "version_date",
"name": "Notice has version date",
"patterns": [r"last\s+updated", r"version", r"effective\s+date", r"date.*notice"],
"weight": 3,
"category": "general",
},
]
# Jurisdiction-specific checks
JURISDICTION_CHECKS: Dict[str, List[Dict]] = {
"DE": [
{"id": "de_widerspruch", "name": "Art. 21 DSGVO Widerspruchsrecht separate section",
"patterns": [r"Widerspruch", r"Art\.?\s*21\s*(DSGVO|GDPR)"], "weight": 5},
{"id": "de_tdddg", "name": "TDDDG telecom/telemedia reference (if applicable)",
"patterns": [r"TDDDG", r"TTDSG", r"Telemedien", r"telemedia"], "weight": 3},
{"id": "de_bdsg", "name": "BDSG reference for employee/DPO provisions",
"patterns": [r"BDSG", r"Bundesdatenschutz", r"§\s*26", r"§\s*38"], "weight": 3},
],
"FR": [
{"id": "fr_cnil", "name": "CNIL reference or guidance compliance",
"patterns": [r"CNIL", r"Commission\s+Nationale"], "weight": 4},
{"id": "fr_lil", "name": "Loi Informatique et Libertés reference",
"patterns": [r"Loi\s+Informatique", r"LIL", r"Informatique\s+et\s+Libert"], "weight": 3},
],
"UK": [
{"id": "uk_ico", "name": "ICO reference as supervisory authority",
"patterns": [r"ICO", r"Information\s+Commissioner"], "weight": 4},
{"id": "uk_gdpr_ref", "name": "UK GDPR (not EU GDPR) references",
"patterns": [r"UK\s+GDPR", r"Data\s+Protection\s+Act\s+2018"], "weight": 3},
{"id": "uk_pecr", "name": "PECR reference for cookies/electronic marketing",
"patterns": [r"PECR", r"Privacy\s+and\s+Electronic\s+Communications"], "weight": 3},
],
"IT": [
{"id": "it_garante", "name": "Garante reference",
"patterns": [r"Garante", r"garanteprivacy"], "weight": 4},
],
"ES": [
{"id": "es_aepd", "name": "AEPD reference",
"patterns": [r"AEPD", r"Agencia\s+Espa"], "weight": 4},
{"id": "es_lopdgdd", "name": "LOPDGDD reference",
"patterns": [r"LOPDGDD", r"Ley\s+Org.nica\s+3/2018"], "weight": 3},
],
"NL": [
{"id": "nl_ap", "name": "AP (Autoriteit Persoonsgegevens) reference",
"patterns": [r"Autoriteit\s+Persoons", r"\bAP\b.*persoons"], "weight": 4},
],
"AT": [
{"id": "at_dsb", "name": "DSB (Datenschutzbehörde) reference",
"patterns": [r"DSB", r"Datenschutzbeh.rde"], "weight": 4},
],
"BE": [
{"id": "be_apd", "name": "APD/GBA reference",
"patterns": [r"APD", r"GBA", r"Gegevensbescherming"], "weight": 4},
],
"IE": [
{"id": "ie_dpc", "name": "DPC (Data Protection Commission) reference",
"patterns": [r"DPC", r"Data\s+Protection\s+Commission"], "weight": 4},
],
}
# Type-specific checks
TYPE_CHECKS: Dict[str, List[Dict]] = {
"website": [
{"id": "web_cookies", "name": "Cookie/tracking technology section",
"patterns": [r"cookie", r"tracking", r"analytics", r"pixel"], "weight": 5},
],
"applicant": [
{"id": "app_retention", "name": "Application data retention period specified",
"patterns": [r"6\s*month", r"applicat.*retain", r"talent\s+pool", r"recruit.*retention"], "weight": 5},
{"id": "app_bdsg26", "name": "Employment law basis for applicant data (DE: §26 BDSG)",
"patterns": [r"§\s*26\s*BDSG", r"employment\s+law", r"recruit.*basis"], "weight": 4},
],
"employee": [
{"id": "emp_works_council", "name": "Works council notification (DE/AT)",
"patterns": [r"works\s+council", r"Betriebsrat", r"employee\s+representative"], "weight": 4},
{"id": "emp_monitoring", "name": "IT monitoring disclosure",
"patterns": [r"monitor", r"surveillance", r"BYOD", r"device\s+management"], "weight": 4},
],
"b2b": [
{"id": "b2b_art14", "name": "Art. 14 source of data disclosure",
"patterns": [r"Art\.?\s*14", r"source.*data", r"not\s+collect.*directly",
r"obtained\s+from", r"indirect.*collection"], "weight": 6},
],
"b2c": [
{"id": "b2c_soft_optin", "name": "Soft opt-in rules for existing customers",
"patterns": [r"soft\s+opt.?in", r"existing\s+customer.*market", r"similar\s+products"], "weight": 4},
],
}
def check_patterns(text: str, patterns: List[str]) -> bool:
"""Check if any pattern matches in text."""
text_lower = text.lower()
for pattern in patterns:
if re.search(pattern, text_lower):
return True
return False
def count_placeholders(text: str) -> int:
"""Count remaining placeholder markers."""
return len(re.findall(r"\[PLACEHOLDER", text, re.IGNORECASE)) + \
len(re.findall(r"\{\{.*?\}\}", text))
def run_checks(text: str, jurisdiction: Optional[str] = None,
notice_type: Optional[str] = None) -> Dict:
"""Run all compliance checks against notice text."""
findings = {
"missing": [],
"present": [],
"general_findings": [],
"jurisdiction_findings": [],
"type_findings": [],
}
total_weight = 0
earned_weight = 0
# Art. 13 mandatory checks
for check in ART13_CHECKS:
total_weight += check["weight"]
if check_patterns(text, check["patterns"]):
earned_weight += check["weight"]
findings["present"].append({
"id": check["id"], "name": check["name"],
"article": check["article"], "status": "present",
})
else:
findings["missing"].append({
"id": check["id"], "name": check["name"],
"article": check["article"], "status": "missing",
"severity": "must-fix",
})
# General checks
for check in GENERAL_CHECKS:
total_weight += check["weight"]
if check["id"] == "no_placeholders":
count = count_placeholders(text)
if count == 0:
earned_weight += check["weight"]
findings["general_findings"].append({
"id": check["id"], "name": check["name"],
"status": "pass", "detail": "No placeholder text found",
})
else:
findings["general_findings"].append({
"id": check["id"], "name": check["name"],
"status": "fail", "detail": f"{count} placeholder(s) remaining",
"severity": "must-fix",
})
elif check_patterns(text, check["patterns"]):
earned_weight += check["weight"]
findings["general_findings"].append({
"id": check["id"], "name": check["name"], "status": "pass",
})
else:
findings["general_findings"].append({
"id": check["id"], "name": check["name"], "status": "fail",
"severity": "should-improve",
})
# Jurisdiction-specific checks
if jurisdiction and jurisdiction in JURISDICTION_CHECKS:
for check in JURISDICTION_CHECKS[jurisdiction]:
total_weight += check["weight"]
if check_patterns(text, check["patterns"]):
earned_weight += check["weight"]
findings["jurisdiction_findings"].append({
"id": check["id"], "name": check["name"],
"status": "pass", "jurisdiction": jurisdiction,
})
else:
findings["jurisdiction_findings"].append({
"id": check["id"], "name": check["name"],
"status": "fail", "jurisdiction": jurisdiction,
"severity": "should-improve",
})
# Type-specific checks
if notice_type and notice_type in TYPE_CHECKS:
for check in TYPE_CHECKS[notice_type]:
total_weight += check["weight"]
if check_patterns(text, check["patterns"]):
earned_weight += check["weight"]
findings["type_findings"].append({
"id": check["id"], "name": check["name"],
"status": "pass", "notice_type": notice_type,
})
else:
findings["type_findings"].append({
"id": check["id"], "name": check["name"],
"status": "fail", "notice_type": notice_type,
"severity": "should-improve",
})
score = round((earned_weight / total_weight) * 100) if total_weight > 0 else 0
return {
"score": score,
"total_checks": len(ART13_CHECKS) + len(GENERAL_CHECKS) +
len(JURISDICTION_CHECKS.get(jurisdiction, [])) +
len(TYPE_CHECKS.get(notice_type, [])),
"mandatory_present": len(findings["present"]),
"mandatory_missing": len(findings["missing"]),
"findings": findings,
}
def format_text_report(results: Dict, jurisdiction: Optional[str],
notice_type: Optional[str]) -> str:
"""Format results as human-readable text."""
lines = []
lines.append("=" * 60)
lines.append("PRIVACY NOTICE COMPLIANCE CHECK")
lines.append(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M')}")
if jurisdiction:
lines.append(f"Jurisdiction: {jurisdiction}")
if notice_type:
lines.append(f"Notice Type: {notice_type}")
lines.append("=" * 60)
score = results["score"]
grade = "EXCELLENT" if score >= 90 else ("GOOD" if score >= 75 else ("NEEDS WORK" if score >= 50 else "INSUFFICIENT"))
lines.append(f"\n Compliance Score: {score}/100 ({grade})")
lines.append(f" Art. 13/14 Elements: {results['mandatory_present']}/{results['mandatory_present'] + results['mandatory_missing']} present")
lines.append(f" Total Checks: {results['total_checks']}")
f = results["findings"]
if f["missing"]:
lines.append(f"\n{'!' * 60}")
lines.append(" MISSING MANDATORY ELEMENTS (must-fix)")
lines.append(f"{'!' * 60}")
for item in f["missing"]:
lines.append(f" [X] {item['name']}")
lines.append(f" Reference: {item['article']}")
general_fails = [g for g in f["general_findings"] if g["status"] == "fail"]
if general_fails:
lines.append(f"\n{'-' * 60}")
lines.append(" GENERAL FINDINGS")
lines.append(f"{'-' * 60}")
for item in general_fails:
detail = f" — {item['detail']}" if "detail" in item else ""
lines.append(f" [!] {item['name']}{detail}")
jur_fails = [j for j in f["jurisdiction_findings"] if j["status"] == "fail"]
if jur_fails:
lines.append(f"\n{'-' * 60}")
lines.append(f" JURISDICTION FINDINGS ({jurisdiction})")
lines.append(f"{'-' * 60}")
for item in jur_fails:
lines.append(f" [!] {item['name']}")
type_fails = [t for t in f["type_findings"] if t["status"] == "fail"]
if type_fails:
lines.append(f"\n{'-' * 60}")
lines.append(f" TYPE-SPECIFIC FINDINGS ({notice_type})")
lines.append(f"{'-' * 60}")
for item in type_fails:
lines.append(f" [!] {item['name']}")
if not f["missing"] and not general_fails and not jur_fails and not type_fails:
lines.append("\n All checks passed.")
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(
description="Validate a privacy notice against Art. 13/14 GDPR requirements"
)
parser.add_argument("notice_file", help="Path to privacy notice file (markdown or text)")
parser.add_argument("--jurisdiction", choices=list(JURISDICTION_CHECKS.keys()),
help="Jurisdiction for local requirements")
parser.add_argument("--notice-type", choices=list(TYPE_CHECKS.keys()),
help="Notice type for type-specific checks")
parser.add_argument("--json", action="store_true", help="Output in JSON format")
args = parser.parse_args()
try:
notice_path = Path(args.notice_file)
if not notice_path.exists():
print(f"Error: File not found: {args.notice_file}", file=sys.stderr)
sys.exit(1)
text = notice_path.read_text(encoding="utf-8")
if not text.strip():
print("Error: Notice file is empty.", file=sys.stderr)
sys.exit(1)
results = run_checks(text, args.jurisdiction, args.notice_type)
results["file"] = str(notice_path)
results["check_date"] = datetime.now().isoformat()
if args.json:
print(json.dumps(results, indent=2))
else:
print(format_text_report(results, args.jurisdiction, args.notice_type))
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Privacy Notice Scaffolder
Generates a privacy notice skeleton based on notice type, jurisdiction, and
processing parameters. Outputs structured markdown with all required sections
pre-populated with jurisdiction-specific placeholders and legal references.
Usage:
python privacy_notice_scaffolder.py --notice-type website --jurisdiction DE --data-categories personal,contact,usage --legal-bases consent,contract
python privacy_notice_scaffolder.py --notice-type employee --jurisdiction FR --data-categories personal,employment --legal-bases contract,legal_obligation --has-ai
python privacy_notice_scaffolder.py --notice-type b2c --jurisdiction UK --data-categories personal,financial --legal-bases consent,contract --has-cookies --json
"""
import argparse
import json
import sys
from datetime import datetime
from typing import Dict, List, Optional
NOTICE_TYPES = ["website", "applicant", "employee", "b2b", "b2c", "combined"]
JURISDICTIONS: Dict[str, Dict] = {
"DE": {
"name": "Germany",
"regulation": "DSGVO (GDPR) + BDSG + TDDDG",
"sa_name": "Relevant Landesbeauftragte or BfDI",
"sa_url": "https://www.bfdi.bund.de",
"language": "German",
"notes": [
"Art. 21 DSGVO right to object must be prominently displayed (separate from other rights)",
"TDDDG (formerly TTDSG) applies to telecom and telemedia services",
"§26 BDSG governs employee data processing (employment context)",
"DSK (Datenschutzkonferenz) guidance should be followed for cookie consent",
],
"dpo_note": "DPO mandatory if 20+ employees regularly engaged in automated processing (§38 BDSG)",
},
"FR": {
"name": "France",
"regulation": "RGPD (GDPR) + Loi Informatique et Libertés (LIL) + LCEN",
"sa_name": "CNIL (Commission Nationale de l'Informatique et des Libertés)",
"sa_url": "https://www.cnil.fr",
"language": "French",
"notes": [
"CNIL recommends specific cookie consent wording and mechanism",
"LIL contains supplementary provisions for research and health data",
"LCEN imposes hosting provider identification requirements",
"French language version required for FR-targeted services",
],
"dpo_note": "DPO appointment follows GDPR Art. 37 criteria",
},
"AT": {
"name": "Austria",
"regulation": "DSGVO (GDPR) + DSG (Datenschutzgesetz)",
"sa_name": "DSB (Datenschutzbehörde)",
"sa_url": "https://www.dsb.gv.at",
"language": "German",
"notes": [
"DSG supplements GDPR with Austrian-specific provisions",
"Employee data subject to works council involvement (ArbVG)",
"DSB has specific guidance on video surveillance",
],
"dpo_note": "DPO appointment follows GDPR Art. 37 criteria",
},
"IT": {
"name": "Italy",
"regulation": "GDPR + Codice Privacy (D.Lgs. 196/2003 as amended)",
"sa_name": "Garante per la protezione dei dati personali",
"sa_url": "https://www.garanteprivacy.it",
"language": "Italian",
"notes": [
"Garante has issued simplified notice guidelines for minors",
"Specific cookie guidelines (Garante Cookie Guidelines 2021)",
"Marketing consent requires granular opt-in (no bundled consent)",
"Simplified notice format available for straightforward processing",
],
"dpo_note": "DPO appointment follows GDPR Art. 37 criteria; Garante recommends broader adoption",
},
"ES": {
"name": "Spain",
"regulation": "GDPR + LOPDGDD (Ley Orgánica 3/2018)",
"sa_name": "AEPD (Agencia Española de Protección de Datos)",
"sa_url": "https://www.aepd.es",
"language": "Spanish",
"notes": [
"LOPDGDD supplements GDPR with Spanish-specific provisions",
"Digital rights provisions (Title X LOPDGDD) including digital disconnection",
"AEPD guidance on employee monitoring and digital rights",
"Deceased persons' data rights (Art. 3 LOPDGDD)",
],
"dpo_note": "Art. 34 LOPDGDD mandates DPO for additional categories beyond GDPR Art. 37",
},
"NL": {
"name": "Netherlands",
"regulation": "GDPR + UAVG (Uitvoeringswet AVG)",
"sa_name": "AP (Autoriteit Persoonsgegevens)",
"sa_url": "https://www.autoriteitpersoonsgegevens.nl",
"language": "Dutch",
"notes": [
"AP has prohibited cookie walls (no access = no consent model)",
"UAVG supplements GDPR for Dutch implementation",
"Specific guidance on BSN (citizen service number) processing",
"AP enforcement active on cookie compliance",
],
"dpo_note": "DPO appointment follows GDPR Art. 37 criteria",
},
"BE": {
"name": "Belgium",
"regulation": "GDPR + Belgian Data Protection Act (30 July 2018)",
"sa_name": "APD/GBA (Autorité de protection des données / Gegevensbeschermingsautoriteit)",
"sa_url": "https://www.gegevensbeschermingsautoriteit.be",
"language": "French / Dutch",
"notes": [
"APD has specific guidance on direct marketing consent",
"Belgian DPA Act supplements GDPR with national provisions",
"Bilingual requirements for notices in bilingual regions",
],
"dpo_note": "DPO appointment follows GDPR Art. 37 criteria",
},
"IE": {
"name": "Ireland",
"regulation": "GDPR + Data Protection Act 2018",
"sa_name": "DPC (Data Protection Commission)",
"sa_url": "https://www.dataprotection.ie",
"language": "English",
"notes": [
"DPC is lead supervisory authority for many US tech companies (one-stop-shop)",
"Specific guidance on cross-border processing under Art. 56",
"DPC enforcement decisions often have EU-wide impact",
"Irish DPA supplements GDPR with national provisions",
],
"dpo_note": "DPO appointment follows GDPR Art. 37 criteria",
},
"UK": {
"name": "United Kingdom",
"regulation": "UK GDPR + Data Protection Act 2018 (UK DPA)",
"sa_name": "ICO (Information Commissioner's Office)",
"sa_url": "https://ico.org.uk",
"language": "English",
"notes": [
"UK GDPR applies post-Brexit (retained EU law)",
"UK International Data Transfer Agreement (IDTA) or UK Addendum to EU SCCs",
"ICO guidance on privacy notices and transparency",
"PECR (Privacy and Electronic Communications Regulations) for cookies and direct marketing",
"ICO registration and data protection fee required",
],
"dpo_note": "DPO appointment follows UK GDPR Art. 37 criteria",
},
}
DATA_CATEGORY_LABELS = {
"personal": "Identity Data (name, date of birth, gender, nationality)",
"contact": "Contact Data (email address, telephone number, postal address)",
"usage": "Usage Data (browsing history, page views, session data, device information)",
"cookies": "Cookie and Tracking Data (cookie identifiers, analytics data, advertising IDs)",
"financial": "Financial Data (payment details, bank account, transaction history)",
"health": "Health Data (medical records, health conditions, disability information)",
"employment": "Employment Data (role, salary, performance, work history, benefits)",
"marketing": "Marketing Data (preferences, consent records, campaign interactions)",
"biometric": "Biometric Data (fingerprints, facial recognition, voice patterns)",
}
LEGAL_BASIS_LABELS = {
"consent": "Art. 6(1)(a) GDPR — Consent",
"contract": "Art. 6(1)(b) GDPR — Performance of a contract",
"legal_obligation": "Art. 6(1)(c) GDPR — Compliance with a legal obligation",
"vital_interests": "Art. 6(1)(d) GDPR — Protection of vital interests",
"public_task": "Art. 6(1)(e) GDPR — Public interest or official authority",
"legitimate_interests": "Art. 6(1)(f) GDPR — Legitimate interests",
}
NOTICE_TYPE_EXTRAS: Dict[str, Dict] = {
"website": {
"title_suffix": "Website/Application",
"extra_sections": ["cookies_tracking"],
"typical_categories": ["personal", "contact", "usage", "cookies", "marketing"],
},
"applicant": {
"title_suffix": "Job Applicants (Recruiting)",
"extra_sections": ["talent_pool"],
"typical_categories": ["personal", "contact", "employment"],
},
"employee": {
"title_suffix": "Employees",
"extra_sections": ["employee_monitoring", "works_council"],
"typical_categories": ["personal", "contact", "employment", "financial", "health"],
},
"b2b": {
"title_suffix": "Business Partners",
"extra_sections": ["art14_source"],
"typical_categories": ["personal", "contact"],
},
"b2c": {
"title_suffix": "Customers",
"extra_sections": ["soft_optin", "payment_processing"],
"typical_categories": ["personal", "contact", "financial", "usage", "marketing"],
},
"combined": {
"title_suffix": "Data Processing",
"extra_sections": [],
"typical_categories": ["personal", "contact", "usage", "financial"],
},
}
def generate_section(num: int, title: str, content: str) -> str:
"""Generate a numbered section."""
return f"## {num}. {title}\n\n{content}\n"
def build_notice(notice_type: str, jurisdiction: str, data_categories: List[str],
legal_bases: List[str], has_cookies: bool, has_ai: bool,
has_transfers: bool) -> str:
"""Build the complete privacy notice skeleton."""
jur = JURISDICTIONS[jurisdiction]
nt = NOTICE_TYPE_EXTRAS[notice_type]
lines = []
# Header
lines.append(f"# Privacy Notice — {nt['title_suffix']}")
lines.append(f"\n**Jurisdiction:** {jur['name']} ({jur['regulation']})")
lines.append(f"**Last Updated:** {datetime.now().strftime('%d %B %Y')}")
lines.append(f"**Version:** 1.0\n")
lines.append("---\n")
sec = 1
# Section 1: Controller Identity
content = ("| Field | Details |\n|-------|--------|\n"
"| Controller | [PLACEHOLDER: Legal entity name and registered address] |\n"
"| Registration | [PLACEHOLDER: Commercial register number] |\n"
"| Contact | [PLACEHOLDER: Email, phone, postal address] |\n"
f"| Supervisory Authority | {jur['sa_name']} — {jur['sa_url']} |\n")
lines.append(generate_section(sec, "Who We Are (Controller Identity)", content))
sec += 1
# Section 2: DPO
content = (f"> {jur['dpo_note']}\n\n"
"| Field | Details |\n|-------|--------|\n"
"| DPO Name | [PLACEHOLDER: DPO name or title] |\n"
"| DPO Contact | [PLACEHOLDER: dpo@company.com] |\n"
"| DPO Address | [PLACEHOLDER: Postal address if different from controller] |\n")
lines.append(generate_section(sec, "Data Protection Officer", content))
sec += 1
# Section 3: Data Categories
content = "We collect and process the following categories of your personal data:\n\n"
content += "| Category | Description | Source |\n|----------|-------------|--------|\n"
for cat in data_categories:
label = DATA_CATEGORY_LABELS.get(cat, cat)
source = "Directly from you" if cat not in ("usage", "cookies") else "Automatically collected"
if notice_type == "b2b":
source = "[PLACEHOLDER: Specify source — directly, from employer, from public sources]"
content += f"| {label} | [PLACEHOLDER: Specific data elements] | {source} |\n"
lines.append(generate_section(sec, "What Data We Collect", content))
sec += 1
# Section 4: Purposes and Legal Bases
content = "| Purpose | Legal Basis | Details |\n|---------|------------|--------|\n"
for basis in legal_bases:
label = LEGAL_BASIS_LABELS.get(basis, basis)
content += f"| [PLACEHOLDER: Specific purpose] | {label} | [PLACEHOLDER: Why this basis applies] |\n"
if "health" in data_categories or "biometric" in data_categories:
content += "\n> **Special Category Data:** Processing of health or biometric data requires an additional legal basis under Art. 9(2) GDPR. [PLACEHOLDER: Specify Art. 9(2) basis — e.g., explicit consent, employment law, vital interests]\n"
lines.append(generate_section(sec, "Why We Process Your Data (Purposes and Legal Bases)", content))
sec += 1
# Section 5: Recipients
content = ("| Recipient Category | Purpose | Location |\n"
"|-------------------|---------|----------|\n"
"| [PLACEHOLDER: IT service providers] | [PLACEHOLDER: Hosting, maintenance] | [PLACEHOLDER: EU/EEA or specify] |\n"
"| [PLACEHOLDER: Payment processors] | [PLACEHOLDER: Payment handling] | [PLACEHOLDER: Country] |\n"
"| [PLACEHOLDER: Analytics providers] | [PLACEHOLDER: Usage analysis] | [PLACEHOLDER: Country] |\n"
"| [PLACEHOLDER: Other recipients] | [PLACEHOLDER: Purpose] | [PLACEHOLDER: Country] |\n")
lines.append(generate_section(sec, "Who Receives Your Data", content))
sec += 1
# Section 6: International Transfers
if has_transfers:
content = ("> We transfer your personal data to recipients outside the EU/EEA. "
"We ensure appropriate safeguards are in place.\n\n"
"| Recipient | Country | Transfer Mechanism | Further Information |\n"
"|-----------|---------|-------------------|--------------------|\n"
"| [PLACEHOLDER] | [PLACEHOLDER] | [PLACEHOLDER: Adequacy decision / SCCs / BCRs] | [PLACEHOLDER: Link to SCCs or further info] |\n")
if jurisdiction == "UK":
content += "\n> **UK Transfers:** Transfers from the UK use the UK International Data Transfer Agreement (IDTA) or UK Addendum to EU SCCs.\n"
else:
content = "Your personal data is processed within the EU/EEA. If transfers outside the EU/EEA become necessary, we will update this notice and ensure appropriate safeguards per Chapter V GDPR.\n"
lines.append(generate_section(sec, "International Data Transfers", content))
sec += 1
# Section 7: Retention
content = ("| Data Category | Retention Period | Basis |\n"
"|--------------|-----------------|-------|\n")
for cat in data_categories:
label = DATA_CATEGORY_LABELS.get(cat, cat).split("(")[0].strip()
content += f"| {label} | [PLACEHOLDER: Specific period or criteria] | [PLACEHOLDER: Legal basis for retention] |\n"
if notice_type == "applicant":
content += "\n> **Applicant Data Default:** Application data is retained for 6 months after the recruitment process concludes, unless you consent to inclusion in our talent pool.\n"
if notice_type == "employee":
content += "\n> **Employee Data:** Retention periods are subject to statutory requirements (e.g., tax records, social security). Specific retention schedules are available from HR.\n"
lines.append(generate_section(sec, "How Long We Keep Your Data", content))
sec += 1
# Section 8: Data Subject Rights
rights_table = ("You have the following rights under GDPR:\n\n"
"| Right | Description | Reference |\n"
"|-------|------------|----------|\n"
"| Access | Request a copy of your personal data | Art. 15 GDPR |\n"
"| Rectification | Request correction of inaccurate data | Art. 16 GDPR |\n"
"| Erasure | Request deletion of your data | Art. 17 GDPR |\n"
"| Restriction | Request limitation of processing | Art. 18 GDPR |\n"
"| Data Portability | Receive your data in a structured format | Art. 20 GDPR |\n"
"| Objection | Object to processing based on legitimate interests | Art. 21 GDPR |\n"
"| Automated Decisions | Right not to be subject to solely automated decisions | Art. 22 GDPR |\n"
"| Withdraw Consent | Withdraw consent at any time without affecting prior processing | Art. 7(3) GDPR |\n"
"\nTo exercise your rights, contact us at [PLACEHOLDER: privacy@company.com].\n")
# Art. 21 prominence for DE
if jurisdiction == "DE":
rights_table += ("\n---\n\n### Right to Object (Widerspruchsrecht) — Art. 21 DSGVO\n\n"
"**You have the right to object at any time, on grounds relating to your particular situation, "
"to the processing of your personal data based on Art. 6(1)(e) or (f) DSGVO. "
"If you object, we will no longer process your data unless we can demonstrate compelling "
"legitimate grounds that override your interests, rights, and freedoms, or the processing "
"serves the establishment, exercise, or defense of legal claims.**\n\n"
"**If we process your personal data for direct marketing purposes, you have the right to "
"object at any time. If you object to processing for direct marketing, we will no longer "
"process your data for these purposes.**\n")
lines.append(generate_section(sec, "Your Rights", rights_table))
sec += 1
# Section 9: Consent Withdrawal
if "consent" in legal_bases:
content = ("Where we process your personal data based on your consent, you have the right to withdraw "
"that consent at any time. Withdrawal does not affect the lawfulness of processing carried "
"out before the withdrawal.\n\n"
"**How to withdraw consent:** [PLACEHOLDER: Describe method — email, settings page, unsubscribe link]\n")
lines.append(generate_section(sec, "Withdrawing Your Consent", content))
sec += 1
# Section 10: Right to Complain
content = (f"You have the right to lodge a complaint with a supervisory authority, in particular in the "
f"Member State of your habitual residence, place of work, or place of the alleged infringement.\n\n"
f"**Your supervisory authority:**\n"
f"- **Name:** {jur['sa_name']}\n"
f"- **Website:** {jur['sa_url']}\n"
f"- **Contact:** [PLACEHOLDER: SA postal address and phone]\n")
lines.append(generate_section(sec, "Right to Complain", content))
sec += 1
# Section 11: Automated Decision-Making
content = ("[PLACEHOLDER: Describe any automated decision-making including profiling per Art. 22 GDPR. "
"If no automated decision-making with legal/significant effects, state: "
"\"We do not use your personal data for automated decision-making that produces legal or similarly significant effects.\"]\n\n"
"If automated decisions are used:\n"
"- Logic involved: [PLACEHOLDER]\n"
"- Significance and consequences: [PLACEHOLDER]\n"
"- Right to human review: [PLACEHOLDER]\n")
lines.append(generate_section(sec, "Automated Decision-Making", content))
sec += 1
# Section 12: Cookies (if applicable)
if has_cookies or "cookies" in data_categories or notice_type == "website":
content = ("| Cookie Category | Examples | Purpose | Consent Required |\n"
"|----------------|---------|---------|------------------|\n"
"| Strictly Necessary | Session, CSRF, load balancer | Essential website function | No |\n"
"| Functional | Language, UI preferences | Enhanced user experience | Yes |\n"
"| Analytics | [PLACEHOLDER: e.g., Google Analytics] | Usage analysis | Yes |\n"
"| Marketing | [PLACEHOLDER: e.g., Facebook Pixel] | Targeted advertising | Yes |\n"
"\nYou can manage your cookie preferences at any time via [PLACEHOLDER: cookie settings link/button].\n")
if jurisdiction == "DE":
content += "\n> **DE Note:** Cookie consent must comply with DSK guidance and TDDDG. Non-essential cookies require prior opt-in consent.\n"
if jurisdiction == "FR":
content += "\n> **FR Note:** Cookie consent must comply with CNIL guidelines. \"Continue browsing\" does not constitute valid consent.\n"
if jurisdiction == "NL":
content += "\n> **NL Note:** Cookie walls are prohibited per AP guidance. Users must be able to access the service without accepting non-essential cookies.\n"
lines.append(generate_section(sec, "Cookies and Tracking Technologies", content))
sec += 1
# Section 13: AI Processing (if applicable)
if has_ai:
content = ("> **EU AI Act (Regulation 2024/1689) Art. 50 Transparency Obligations**\n\n"
"| AI System | Purpose | Risk Level | Human Oversight |\n"
"|-----------|---------|-----------|----------------|\n"
"| [PLACEHOLDER: AI system name] | [PLACEHOLDER: Purpose] | [PLACEHOLDER: High/Limited/Minimal] | [PLACEHOLDER: Description] |\n"
"\n**How AI affects you:**\n"
"- [PLACEHOLDER: What decisions or outputs AI influences]\n"
"- [PLACEHOLDER: Your rights regarding AI processing]\n"
"- [PLACEHOLDER: How to request human review]\n")
lines.append(generate_section(sec, "AI and Automated Processing", content))
sec += 1
# Type-specific sections
if notice_type == "applicant":
content = ("If your application is unsuccessful, we may ask for your consent to retain your data "
"in our talent pool for future opportunities.\n\n"
"- **Retention in talent pool:** [PLACEHOLDER: Period, e.g., 12 months]\n"
"- **Consent mechanism:** [PLACEHOLDER: How consent is obtained]\n"
"- **Withdrawal:** You can request removal from the talent pool at any time.\n")
lines.append(generate_section(sec, "Talent Pool", content))
sec += 1
if notice_type == "employee":
if jurisdiction in ("DE", "AT"):
content = ("Your employer may be required to inform the works council (Betriebsrat) about "
"certain data processing activities in accordance with the Works Constitution Act "
"(Betriebsverfassungsgesetz).\n\n"
"- [PLACEHOLDER: Describe works council notification scope]\n"
"- [PLACEHOLDER: IT monitoring arrangements agreed with works council]\n"
"- [PLACEHOLDER: BYOD policy if applicable]\n")
else:
content = ("- [PLACEHOLDER: Employee representative body notification if applicable]\n"
"- [PLACEHOLDER: IT monitoring policy and scope]\n"
"- [PLACEHOLDER: BYOD policy if applicable]\n")
lines.append(generate_section(sec, "Employee-Specific Information", content))
sec += 1
if notice_type == "b2b":
content = ("Where we have not collected your personal data directly from you, we are required "
"under Art. 14 GDPR to inform you of the source.\n\n"
"| Source Category | Data Obtained | Publicly Available |\n"
"|----------------|--------------|-------------------|\n"
"| [PLACEHOLDER: Your employer] | Contact details, role | [PLACEHOLDER: Yes/No] |\n"
"| [PLACEHOLDER: Business registers] | Company details | Yes |\n"
"| [PLACEHOLDER: Industry databases] | Professional contact details | [PLACEHOLDER: Yes/No] |\n")
lines.append(generate_section(sec, "Source of Your Data (Art. 14 GDPR)", content))
sec += 1
# Jurisdiction notes
if jur["notes"]:
lines.append(f"## Jurisdiction-Specific Notes ({jur['name']})\n")
for note in jur["notes"]:
lines.append(f"- {note}")
lines.append("")
# Footer
lines.append("---\n")
lines.append(f"*This privacy notice was generated on {datetime.now().strftime('%Y-%m-%d')} "
f"for {jur['name']} jurisdiction. All [PLACEHOLDER] markers must be replaced "
f"with actual information before publication. Legal review is required.*\n")
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(
description="Generate a privacy notice skeleton with jurisdiction-specific placeholders"
)
parser.add_argument("--notice-type", required=True, choices=NOTICE_TYPES,
help="Notice type: website, applicant, employee, b2b, b2c, combined")
parser.add_argument("--jurisdiction", required=True, choices=list(JURISDICTIONS.keys()),
help="Jurisdiction code: DE, FR, AT, IT, ES, NL, BE, IE, UK")
parser.add_argument("--data-categories", required=True,
help="Comma-separated data categories: personal,contact,usage,cookies,financial,health,employment,marketing,biometric")
parser.add_argument("--legal-bases", required=True,
help="Comma-separated legal bases: consent,contract,legal_obligation,legitimate_interests,vital_interests,public_task")
parser.add_argument("--has-cookies", action="store_true", help="Include cookies and tracking section")
parser.add_argument("--has-ai", action="store_true", help="Include AI and automated processing section")
parser.add_argument("--has-international-transfers", action="store_true",
help="Include international transfers section")
parser.add_argument("--json", action="store_true", help="Output in JSON format")
args = parser.parse_args()
try:
categories = [c.strip() for c in args.data_categories.split(",")]
bases = [b.strip() for b in args.legal_bases.split(",")]
# Validate categories
valid_cats = set(DATA_CATEGORY_LABELS.keys())
for cat in categories:
if cat not in valid_cats:
print(f"Warning: Unknown data category '{cat}'. Valid: {', '.join(sorted(valid_cats))}", file=sys.stderr)
# Validate bases
valid_bases = set(LEGAL_BASIS_LABELS.keys())
for basis in bases:
if basis not in valid_bases:
print(f"Warning: Unknown legal basis '{basis}'. Valid: {', '.join(sorted(valid_bases))}", file=sys.stderr)
notice = build_notice(
args.notice_type, args.jurisdiction, categories, bases,
args.has_cookies, args.has_ai, args.has_international_transfers
)
if args.json:
output = {
"generated": datetime.now().isoformat(),
"parameters": {
"notice_type": args.notice_type,
"jurisdiction": args.jurisdiction,
"data_categories": categories,
"legal_bases": bases,
"has_cookies": args.has_cookies,
"has_ai": args.has_ai,
"has_international_transfers": args.has_international_transfers,
},
"notice_markdown": notice,
"placeholder_count": notice.count("[PLACEHOLDER"),
"jurisdiction_info": JURISDICTIONS[args.jurisdiction],
}
print(json.dumps(output, indent=2))
else:
print(notice)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()
Related skills
FAQ
Which notice types and jurisdictions are supported?
6 notice types (website, applicant, employee, b2b, b2c, combined) across 9 jurisdictions: DE, FR, AT, IT, ES, NL, BE, IE, UK.
How does the compliance checker score notices?
It validates against Art. 13/14 GDPR requirements and returns a compliance score of 0-100 with missing and incomplete elements.