Your code collects data without you knowing? A hidden form, a log writing emails in plain text, a cookie tracking before consent. It happens more often than you think. And it's not just a legal problem: it's a software quality issue. We at Meteora Web see it every time we analyze inherited projects: personal data scattered everywhere, no minimization principle, no protection by default. Privacy by design is not a GDPR checklist: it's a way of thinking about code architecture. In this guide we show how to really implement it, with concrete examples in PHP, JavaScript, and databases.
What Is Privacy by Design in Code Implementation?
Privacy by design means that data protection is not a final addition but a functional requirement like security or performance. The 7 foundational principles (from Ann Cavoukian's work) translate into precise technical choices. Let's focus on the two most operational ones:
- Proactive not reactive: code must not allow data leaks even in case of error. Example: a try-catch that logs the full exception (with user variables) is a violation.
- Privacy as the default setting: if a data point is not needed, don't collect it. If a user does not explicitly consent, the default behavior is maximum privacy.
We translate these into concrete rules: no personal data in logs, no sequential IDs in URLs, no collection without verifiable consent.
Sponsored Protocol
How to Implement Data Minimization in Code?
The most violated principle. Massive collection "just in case we need it" — but GDPR requires every field to be justified. In code this means:
- Never ask for data not necessary for the current functionality.
- If you can use an anonymous identifier (UUID) instead of email, do it.
- In forms, do not include hidden fields with sensitive data. A hidden field with "userId" or "role" is a risk.
Practical example: minimal login in PHP
// Wrong: collects and logs email + IP + user agent
$stmt = $pdo->prepare('INSERT INTO log_accessi (email, ip, user_agent, timestamp) VALUES (?,?,?,?)');
// Right: logs only timestamp and a hash of the IP (anonymization)
$ipHash = hash('sha256', $_SERVER['REMOTE_ADDR'] . SALT);
$stmt = $pdo->prepare('INSERT INTO log_accessi (ip_hash, timestamp) VALUES (?,?)');
Do this now: check every INSERT or log in your project. Every field that contains name, email, phone must be justified with an explicit purpose. If it's not essential, don't save it.
Privacy by Default: How to Make Consent Effective in the Frontend?
Many sites load tracking before the user clicks "Accept". That's a violation. Privacy by default means that no third-party script should run without active consent. Practical implementation with vanilla JavaScript:
Sponsored Protocol
// Lightweight cookie consent manager
const consent = localStorage.getItem('consent_tracking');
if (consent === 'granted') {
loadGoogleAnalytics();
loadFacebookPixel();
}
function loadGoogleAnalytics() {
// Load GA4 only after consent
const script = document.createElement('script');
script.src = 'https://www.googletagmanager.com/gtag/js?id=G-XXXXX';
document.head.appendChild(script);
}
Beware: hiding the cookie banner is not enough. You must prevent actual loading. We use a server-side tag manager (Stape or similar) to have full control over what gets sent.
Consent code checklist
- No third-party scripts in unless strictly technical.
- Every pixel or tracker has a consent state variable before loading.
- The consent form must record the choice with timestamp and policy version.
How to Protect Data in APIs and URLs?
Classic mistakes: user ID in URL (e.g., /user/123), passwords in query string, JWT tokens in logs. Privacy by design requires that no personal data is unintentionally exposed.
Use UUID instead of sequential IDs
// Instead of /profile/42
// Use /profile/550e8400-e29b-41d4-a716-446655440000
$stmt = $pdo->prepare('SELECT * FROM users WHERE uuid = ?');
$stmt->execute([$uuid]);
Benefit: even if a user guesses another UUID, they cannot predict the next one. It does not expose the number of subscribers. It does not leak business growth data.
Sponsored Protocol
Never log API request bodies in plain text
// Wrong
file_put_contents('api.log', json_encode($_POST) . PHP_EOL, FILE_APPEND);
// Right: log only timestamp, endpoint, and status code
file_put_contents('api.log', sprintf("[%s] %s %d\n", date('c'), $_SERVER['REQUEST_URI'], http_response_code()), FILE_APPEND);
Do this now: search your code for `var_dump($_POST)`, `json_encode($request)` or `print_r($user)` used for debugging. Replace them with anonymized logs.
How to Handle Data Deletion on Request (Right to Erasure)?
A "Delete account" button is not enough. Privacy by design means that code must guarantee complete and verifiable deletion. Real cases we encountered:
- User data spread across 5 different tables (profile, orders, logs, newsletter, wallet).
- Daily backups that keep deleted data for months.
- Cron jobs that restore data from old dumps.
Implement soft delete + hard delete
// Add deleted_at column to every table with personal data
ALTER TABLE users ADD deleted_at TIMESTAMP NULL DEFAULT NULL;
// For soft delete
UPDATE users SET deleted_at = NOW() WHERE id = ?;
// Hard delete after retention period (e.g., 30 days)
DELETE FROM users WHERE deleted_at IS NOT NULL AND deleted_at < DATE_SUB(NOW(), INTERVAL 30 DAY);
Note: soft delete is not enough if personal data must be removed immediately (e.g., GDPR request). Then you must hard delete on all involved tables, and also update backups (or at least anonymize the records).
Sponsored Protocol
Anonymization instead of deletion
Sometimes you can't delete a record (e.g., tax invoice). In that case anonymize all personal data: replace name with "Deleted user", email with a hash, address with empty.
UPDATE orders
SET name = 'Deleted',
email = CONCAT('deleted','@','example.com'),
address = ''
WHERE user_id = ?;
How to Verify That Code Respects Privacy by Design?
Writing careful code is not enough: you need a continuous verification process. Practical tools:
- Static analysis: use PHPStan with custom rules to forbid functions like `var_dump` in production, logging of superglobals, etc.
- Code review checklist: every PR must include a "privacy impact" section — what data is touched, where it ends up, how it's protected.
- Penetration test focused on data: simulate an attack that tries to extract personal data from logs, URLs, API responses.
Example PHPStan rule
// In phpstan.neon
parameters:
rules:
- MeteoraWeb\Privacy\NoVarDumpRule
We created an internal PHPStan rule library to block `print_r`, `var_dump`, `json_encode` on non-anonymized user data. You can start with a simple custom sniff or use tools like Psalm with taint analysis.
Sponsored Protocol
What to Do Next
Privacy by design is not a one-time project: it's a development habit. Here are 3 steps you can take today:
- Quick log audit: search your project for all occurrences of `error_log`, `file_put_contents`, `var_dump`, `console.log`. Check if they contain personal data. Anonymize or remove them immediately.
- Implement explicit consent: move all tracking scripts behind a state variable. If you don't have a cookie manager yet, use the vanilla JavaScript code above as a starting point.
- Plan for erasure: write a stored procedure or script that can delete/anonymize a user on request, across all tables. Test it in staging before going to production.
For further technical reading, check our pillar on Privacy and GDPR for Developers and the article on Secure JWT — another key piece for data protection.