InsightsLaravel Development
Laravel DevelopmentLaravelBackend DevelopmentAPI ArchitectureDatabase Architecture

Saudi PDPL Compliance Laravel Guide

Implement Saudi PDPL compliance in Laravel with real code: consent logging, true deletion routines, retention policies, and data residency checks.

U

Umar Farooq

System Architect & Full-Stack Engineer

October 23, 2026
7 min read
Saudi PDPL Compliance Laravel Guide

Saudi PDPL Compliance in Laravel: Consent and Deletion as Code

Saudi Arabia's Personal Data Protection Law is actively enforced, with significant fines publicly reported. Most teams hear "PDPL compliance" and think paperwork. The failures that draw penalties live in the code: missing consent records, soft deletes presented as deletion, data with no retention policy, backups nobody can purge. Saudi PDPL compliance in Laravel is an engineering task.

Quick Answer: Implement Saudi PDPL in Laravel with four concrete mechanisms: an append-only consent log recording what each user agreed to and when, true deletion routines that purge personal data instead of soft-deleting it, automated retention policies that expire data on schedule, and data residency checks keeping Saudi user data on approved infrastructure. Each one is a few dozen lines of code, and together they cover the obligations auditors actually test.

What PDPL Actually Requires of Your Code

Strip away the legal language and the law asks for engineering behaviors: collect only for a stated purpose, get consent and record it, let users see, correct, and delete their data, keep it only as long as necessary, protect it while held, and keep Saudi residents' data on compliant infrastructure.

Notice what is missing: no checkbox says "install a cookie banner and you are done." Banners are the visible one percent; the rest is database design, queue jobs, log pipelines, and backup policies. When I audit a Laravel app for PDPL readiness, I start with the migrations. If you are adding national identity verification, read my Nafath authentication guide first.

Consent is the foundation, and "the user clicked accept" is not a record. A defensible log captures who consented, to what, which terms version they saw, when, and through which channel. It must be append-only, because the log itself is your evidence.

In Laravel this is a dedicated table kept outside your soft-delete patterns. A consent record should survive even the user's deletion request in anonymized form, since you may need to prove consent for the period you held their data.

<?php

// Migration: consent records are append-only. No soft deletes,
// no updates through the application. History is the evidence.

Schema::create('consent_logs', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constrained()->cascadeOnDelete();
    $table->string('purpose');          // e.g. 'marketing', 'analytics'
    $table->string('terms_version');    // e.g. 'privacy-policy-v3'
    $table->enum('action', ['granted', 'withdrawn']);
    $table->string('channel');          // 'web', 'mobile', 'api'
    $table->ipAddress('ip_address')->nullable();
    $table->timestamp('recorded_at')->useCurrent();
    $table->index(['user_id', 'purpose']);
});

// Recording consent: one line, called from registration,
// settings updates, and checkout flows alike.

ConsentLog::create([
    'user_id'       => $user->id,
    'purpose'       => 'marketing',
    'terms_version' => config('legal.privacy_version'),
    'action'        => 'granted',
    'channel'       => 'web',
    'ip_address'    => $request->ip(),
]);

The detail most teams miss is the terms version. A boolean accepted_terms column tells you nothing about what the user agreed to; the version string tells you everything. Store it on every consent event.

True Deletion, Not Soft Deletes

Here is where Laravel's SoftDeletes trait becomes a liability. Soft delete hides the row; the personal data sits in your database indefinitely. Under PDPL, that data must actually go away. A deleted_at column is not deletion, it is archiving with extra steps.

Keep soft deletes for operational recovery, but pair every soft-deletable personal model with a hard-purge routine after a grace period. Thirty days is a common choice: long enough for recovery and disputes, short enough to defend.

<?php

namespace App\Console\Commands;

use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;

class PurgeDeletedPersonalData extends Command
{
    protected $signature = 'pdpl:purge-expired';
    protected $description = 'Hard-delete personal data past retention.';

    public function handle(): int
    {
        // Grace period comes from config, not hardcoded:
        // different data classes can carry different periods.
        $cutoff = now()->subDays(config('pdpl.purge_grace_days', 30));

        DB::transaction(function () use ($cutoff) {
            $users = User::onlyTrashed()
                ->where('deleted_at', '<', $cutoff)
                ->cursor();

            foreach ($users as $user) {
                // Anonymize what must survive (invoices, audit trails),
                // then destroy the personal record itself.
                $user->orders()->update(['customer_name' => '[deleted]']);
                $user->consentLogs()->update(['ip_address' => null]);
                $user->forceDelete();
            }
        });

        $this->info('Purge complete.');
        return self::SUCCESS;
    }
}

Run it on the scheduler nightly, logging counts not identities. And remember backups: a purge routine that cleans the live database while backups retain the data for a year is theater. Align backup retention with data retention and document it.

Retention Policies and Data Residency

Retention is the quiet killer. Onboarding data from 2023 still sitting in a users table in 2026, long after the account went dormant, is a violation waiting for a complaint. Give every personal-data table a retention rule in config and enforce it with scheduled jobs. Policy without enforcement is a document, not compliance.

Data residency is the infrastructure half. Saudi user data belongs on infrastructure satisfying PDPL transfer requirements, not a default US region because that was the tutorial default. Choose your database region deliberately, check where queue workers and log aggregators ship data, and read vendors' data processing terms first. A Riyadh-region database streaming logs to a US analytics service has a residency gap no banner can fix. This is standard architecture review work, the kind I do for engineering teams in Riyadh.

PDPL obligation mapped to its code implementation:

PDPL obligation

The code that satisfies it

Where it lives

Consent before collection

Append-only consent log with terms version

Migration + one-liner at collection points

Right to deletion

Hard-purge routine after grace period

Artisan command on scheduler

Storage limitation

Per-table retention rules, enforced nightly

Config + scheduled jobs

Data residency

Region-pinned infrastructure, vendor review

Infrastructure config, architecture docs

Security

Encryption at rest, hashed lookups, minimal logging

Model casts, logging config

Accountability

Purge run logs (counts only), policy versions

Log channels, versioned docs

No. A banner covers browser tracking consent; PDPL covers everything your backend stores and processes. Teams that stop at the banner still fail on deletion, retention, and residency. Do the database work in this guide first.

Can I keep anonymized data after deleting a user?

Generally yes, if anonymization is genuine: no identifiers, no reasonable re-identification path. Hashing an email is pseudonymization, not anonymization. When in doubt, delete more.

How do backups affect deletion requests?

They complicate them, so plan upfront. Align backup retention with data retention, document it, and ensure restores do not resurrect purged data. Some teams re-run purge routines automatically after any restore.

What about third-party services like analytics and email providers?

You are responsible for data you send them. Review each vendor's data processing terms, confirm storage locations, and drop vendors that cannot answer. Strip personal identifiers from analytics payloads before they leave your servers.

Summary & Production Takeaways

Saudi PDPL compliance in Laravel comes down to four habits: log consent immutably with terms versions, purge truly instead of soft-deleting, enforce retention on a schedule, and pin data to compliant infrastructure. None of it is exotic; all of it gets skipped until an audit forces the issue. Build it in now, while it is a few dozen lines of code. To have your application reviewed against these obligations, book a technical scoping call.

Umar Farooq - Full-Stack & AI Engineer

Umar Farooq

Author & Consultant

Specializes in Laravel, Next.js, and AI products. 5+ years enterprise experience with 80+ delivered platforms and full source code ownership.

Did you find this architecture breakdown useful?