Implementation of Personal Data Processing Consent Form by Categories
Consent form by categories allows user to grant or withdraw consent separately for each data processing purpose. GDPR requires this: consent must be specific, not a single "agree to everything."
Consent Categories
Standard set for web service:
| Category | Description | Required |
|---|---|---|
| Necessary | Service operation | Always enabled |
| Analytics | Service improvement, Google Analytics | Optional |
| Marketing | Personalized advertising | Optional |
| Preferences | Remember settings | Optional |
| Third-party | Third-party services (chat, maps) | Optional |
Frontend Implementation
// ConsentBanner.jsx
import { useState, useEffect } from 'react'
const CONSENT_KEY = 'user_consent_v2'
const CATEGORIES = [
{
id: 'necessary',
name: 'Necessary',
description: 'Authentication, security, basic functionality',
required: true
},
{
id: 'analytics',
name: 'Analytics',
description: 'Google Analytics for service improvement',
required: false
},
{
id: 'marketing',
name: 'Marketing',
description: 'Personalized advertising and retargeting',
required: false
},
{
id: 'preferences',
name: 'Preferences',
description: 'Remember language, theme and other preferences',
required: false
}
]
function ConsentBanner() {
const [visible, setVisible] = useState(false)
const [showDetails, setShowDetails] = useState(false)
const [consents, setConsents] = useState({
necessary: true,
analytics: false,
marketing: false,
preferences: false
})
useEffect(() => {
const stored = localStorage.getItem(CONSENT_KEY)
if (!stored) setVisible(true)
else applyConsents(JSON.parse(stored))
}, [])
const acceptAll = () => {
const all = Object.fromEntries(CATEGORIES.map(c => [c.id, true]))
saveConsents(all)
}
const rejectOptional = () => {
const minimal = Object.fromEntries(
CATEGORIES.map(c => [c.id, c.required])
)
saveConsents(minimal)
}
const saveConsents = (consent) => {
localStorage.setItem(CONSENT_KEY, JSON.stringify({
...consent,
version: 'v2024-03',
timestamp: new Date().toISOString()
}))
applyConsents(consent)
setVisible(false)
reportConsentToServer(consent)
}
const applyConsents = (consent) => {
if (consent.analytics) initAnalytics()
if (consent.marketing) initMarketing()
}
if (!visible) return null
return (
<div className="consent-banner" role="dialog" aria-label="Cookie settings">
<h3>We use cookies</h3>
<p>For site operation and improving your experience.</p>
{showDetails && (
<div className="consent-categories">
{CATEGORIES.map(cat => (
<label key={cat.id} className="consent-category">
<input
type="checkbox"
checked={consents[cat.id]}
disabled={cat.required}
onChange={e => setConsents(prev => ({
...prev,
[cat.id]: e.target.checked
}))}
/>
<div>
<strong>{cat.name}</strong>
<p>{cat.description}</p>
</div>
</label>
))}
</div>
)}
<div className="consent-actions">
<button onClick={acceptAll}>Accept all</button>
<button onClick={rejectOptional}>Only necessary</button>
{showDetails
? <button onClick={() => saveConsents(consents)}>Save settings</button>
: <button onClick={() => setShowDetails(true)}>Configure</button>
}
</div>
</div>
)
}
Saving Consents on Server
@app.route('/api/consent', methods=['POST'])
def save_consent():
data = request.json
user_id = current_user.id if current_user.is_authenticated else None
consent_record = {
'user_id': user_id,
'session_id': session.get('id'),
'ip': request.remote_addr,
'user_agent': request.user_agent.string,
'consent_data': data['consents'],
'version': data.get('version'),
'timestamp': datetime.utcnow(),
'method': 'banner'
}
db.execute("""
INSERT INTO consent_log
(user_id, session_id, ip, user_agent, consent_data, version, accepted_at, method)
VALUES (%(user_id)s, %(session_id)s, %(ip)s, %(user_agent)s,
%(consent_data)s::jsonb, %(version)s, %(timestamp)s, %(method)s)
""", consent_record)
return jsonify({'status': 'saved'})
Applying Consents to Third-Party Scripts
function applyConsents(consents) {
// Google Analytics
if (consents.analytics) {
window['ga-disable-G-XXXXXXXX'] = false
gtag('consent', 'update', {
analytics_storage: 'granted'
})
} else {
window['ga-disable-G-XXXXXXXX'] = true
gtag('consent', 'update', {
analytics_storage: 'denied'
})
}
// Facebook Pixel
if (consents.marketing) {
fbq('consent', 'grant')
} else {
fbq('consent', 'revoke')
}
}
// Google Consent Mode v2 (required for Google Ads since May 2024)
gtag('consent', 'default', {
analytics_storage: 'denied',
ad_storage: 'denied',
ad_user_data: 'denied',
ad_personalization: 'denied',
wait_for_update: 500
})







