GDPR Art.26: Joint Controllers — Shared Data Responsibility, Arrangements & Engineering Patterns (2026)
Post #425 in the sota.io EU Cyber Compliance Series
Art.26 addresses one of the least-understood liability structures in data protection law: joint controllership. When two organisations co-determine why and how data is processed, they do not get to split the GDPR burden arbitrarily — the regulation binds them both, in full, and data subjects can enforce rights against either party regardless of internal allocation agreements.
For developers and platform engineers this matters directly: embedded analytics pixels, shared infrastructure, partner APIs, co-branded products, and multi-tenant SaaS architectures frequently create joint controllership without the engineering teams realising it.
GDPR Chapter IV: Art.26 in Context
| Article | Role | Primary Obligation | Relationship |
|---|---|---|---|
| Art.24 | Controller accountability | Implement + demonstrate TOMs | Sole or joint |
| Art.25 | Privacy by Design | Build data minimisation into architecture | Sole or joint |
| Art.26 | Joint Controllers | Arrange responsibilities; expose contact point to data subjects | Two or more controllers |
| Art.27 | EU Representative | Designate representative if non-EU controller | Non-EU controllers |
| Art.28 | Processor obligations | DPA with every processor | Controller–Processor |
| Art.29 | Processing under authority | Staff process only on instruction | Controller–Staff/Processor |
| Art.30 | Records of processing | RoPA per controller | Each entity |
The crucial classification: Art.26 (joint controller) ≠ Art.28 (processor). A processor acts on behalf of the controller and has no independent purpose. A joint controller co-determines the purpose — even if the processing is technically executed by only one party.
The "Jointly Determine" Test
Art.26(1) is triggered when two or more controllers jointly determine the purposes and means of processing. Four CJEU rulings have progressively clarified what "jointly determine" means in practice.
CJEU Case Law: The Four Pillars
1. Wirtschaftsakademie (C-210/16, 2018) Facebook Page administrators were held to be joint controllers with Facebook for the processing of visitor statistics through Facebook Insights. The key finding: you do not need to have technical access to the personal data to be a joint controller — determining that processing will occur (by creating the Page and enabling Insights) is sufficient.
2. Fashion ID (C-40/17, 2019) An e-commerce website that embedded the Facebook Like button was held to be a joint controller with Facebook for the collection and transmission phase (but not the subsequent Facebook-side processing). Critical clarification: joint controllership can be phase-limited — you are jointly responsible for the processing operations you have influenced, not necessarily all downstream processing.
3. Facebook Ireland / Belgium (C-645/19, 2021) The CJEU confirmed that a lead supervisory authority (LSA) under the Art.60 consistency mechanism cannot divest other DPAs of jurisdiction over processing that affects local residents. For joint controllers with an EU establishment, this means any DPA in any affected Member State can act.
4. Meta Platforms (C-252/21, 2023) The Bundeskartellamt case: the CJEU confirmed that a competition authority can assess GDPR violations as part of an abuse-of-dominance analysis, and that Meta's unlawful data processing (absent valid consent) constituted a relevant factor. Implication: GDPR joint controllership failures can trigger parallel enforcement by competition regulators.
The Practical Test
Three questions determine whether Art.26 applies:
| Question | If YES | If NO |
|---|---|---|
| Does Organisation B process data collected or initiated by Organisation A's system? | Possible joint control | Likely independent control |
| Does Organisation A influence why Organisation B processes the data (purpose)? | Joint control likely | Processor relationship possible |
| Does Organisation A influence how Organisation B processes the data (means)? | Joint control confirmed | Further analysis needed |
Common False Negatives — situations teams incorrectly classify as processor relationships:
- Analytics SDKs: Embedding Amplitude, Mixpanel, or Segment where both parties receive event data and each can define custom event schemas → joint control for the collection phase
- Co-branded products: Two companies share a customer dataset for a jointly marketed product → joint control for the entire processing lifecycle
- Shared infrastructure: Two subsidiaries use a common IAM system with shared user profiles → joint control between the subsidiaries (even if the parent operates the infrastructure as processor)
- Affiliate tracking: An affiliate network that receives first-party click/conversion data from a merchant's site and attributes conversions → typically joint control for the attribution processing
Art.26(1): The Arrangement Requirement
When joint controllership exists, Art.26(1) mandates a transparent arrangement that determines:
- Respective responsibilities for complying with GDPR obligations
- Allocation of Art.13/14 transparency obligations (who provides the privacy notice?)
- Allocation of Art.15–22 rights fulfilment (who receives and responds to DSARs?)
- Allocation of Art.33/34 breach notification obligations (who notifies the DPA and data subjects?)
- Allocation of Art.30 RoPA maintenance (each controller must maintain their own record)
The arrangement is not optional and cannot be replaced by reliance on another legal instrument. Critically: the arrangement does not affect the data subject's right to exercise rights against either controller (Art.26(3)). Internal allocation of responsibility shifts liability between joint controllers, but does not reduce either controller's obligation to the data subject.
Joint Controller Agreement (JCA) — Required Elements
from dataclasses import dataclass, field
from typing import Optional
from datetime import date
@dataclass
class JointControllerArrangement:
"""
Art.26(1) GDPR — Joint Controller Agreement structure.
Both parties sign; essence disclosed per Art.26(2).
"""
party_a_name: str
party_a_dpo_contact: str # Art.37 DPO contact or Art.27 representative
party_b_name: str
party_b_dpo_contact: str
effective_date: date
processing_description: str # What processing is jointly controlled
legal_basis: str # e.g. "Art.6(1)(b) — contract performance"
# Responsibility allocation
transparency_party: str # "A", "B", or "both"
dsar_primary_contact: str # Which party receives rights requests first
dsar_response_sla_days: int = 30 # Art.12(3) — 1 month default
breach_notification_party: str # Who notifies DPA under Art.33
# Contact point exposed to data subjects (Art.26(2))
data_subject_contact_point: str # Email / form URL — must be publicly disclosed
data_subject_contact_party: str # "A", "B", or "both"
# Downstream arrangements
processor_dpa_party: str # Who signs Art.28 DPAs with sub-processors
sub_processor_list_url: Optional[str] = None
def validate(self) -> list[str]:
errors = []
if self.transparency_party not in ("A", "B", "both"):
errors.append("transparency_party must be A, B, or both")
if self.dsar_primary_contact not in ("A", "B"):
errors.append("dsar_primary_contact must be A or B")
if self.breach_notification_party not in ("A", "B", "both"):
errors.append("breach_notification_party must be A, B, or both")
if not self.data_subject_contact_point.startswith(("http", "mailto:")):
errors.append("data_subject_contact_point must be a URL or mailto:")
return errors
Minimum Public Disclosure (Art.26(2))
The essence of the arrangement must be made available to data subjects. This does not require publishing the full commercial agreement — but must include at minimum:
- The identity of both controllers
- The contact point where data subjects can exercise rights
- Which controller is the primary point of contact for rights requests
// Privacy notice component — Art.26(2) disclosure
interface JointControllerDisclosure {
controllerA: { name: string; country: string; contact: string };
controllerB: { name: string; country: string; contact: string };
primaryContact: "A" | "B";
dataSubjectContactUrl: string;
arrangementSummary: string; // Plain-language essence
}
function JointControllerNotice({ disclosure }: { disclosure: JointControllerDisclosure }) {
const primary =
disclosure.primaryContact === "A" ? disclosure.controllerA : disclosure.controllerB;
return (
<section aria-label="Joint controller information">
<p>
This service is operated jointly by{" "}
<strong>{disclosure.controllerA.name}</strong> ({disclosure.controllerA.country}) and{" "}
<strong>{disclosure.controllerB.name}</strong> ({disclosure.controllerB.country}).
</p>
<p>
{disclosure.arrangementSummary}
</p>
<p>
To exercise your data subject rights, contact:{" "}
<a href={disclosure.dataSubjectContactUrl}>{primary.name} — Privacy Team</a>
</p>
</section>
);
}
Art.26(3): Data Subject Rights Against Either Controller
This is the provision that most engineering teams miss. Regardless of the internal JCA, any data subject can exercise any Art.15–22 right against either controller. Each controller must be able to:
- Receive and acknowledge a rights request
- Either fulfil it independently, or
- Route it to the designated controller within a timeframe that still meets the Art.12(3) 1-month deadline
Rights Routing Architecture
import httpx
from enum import Enum
from datetime import datetime, timedelta
class DSARRoutingDecision(Enum):
FULFIL_LOCALLY = "fulfil_locally"
ROUTE_TO_PARTNER = "route_to_partner"
FULFIL_JOINTLY = "fulfil_jointly"
class JointControllerDSARRouter:
"""
Routes incoming DSAR to correct party, preserving Art.12(3) deadline.
The receiving controller has full 30-day obligation regardless of routing.
"""
def __init__(self, arrangement: JointControllerArrangement, partner_api_url: str):
self.arrangement = arrangement
self.partner_api_url = partner_api_url
# Internal routing deadline: route within 5 days to leave partner 25 days
self.internal_routing_deadline_days = 5
def receive_request(
self,
request_type: str, # "access", "erasure", "portability", etc.
data_subject_id: str,
received_at: datetime,
) -> dict:
"""
Step 1: Acknowledge immediately (within 72h best practice).
Step 2: Determine routing.
Step 3: If routing to partner, send within internal_routing_deadline_days.
"""
legal_deadline = received_at + timedelta(days=30)
routing_deadline = received_at + timedelta(days=self.internal_routing_deadline_days)
routing = self._determine_routing(request_type)
record = {
"request_id": f"DSAR-{data_subject_id}-{received_at.isoformat()}",
"request_type": request_type,
"received_by": "party_a",
"received_at": received_at.isoformat(),
"legal_deadline": legal_deadline.isoformat(),
"routing": routing.value,
"routing_deadline": routing_deadline.isoformat() if routing == DSARRoutingDecision.ROUTE_TO_PARTNER else None,
"status": "received",
}
if routing == DSARRoutingDecision.ROUTE_TO_PARTNER:
self._notify_partner(record)
return record
def _determine_routing(self, request_type: str) -> DSARRoutingDecision:
primary = self.arrangement.dsar_primary_contact
if primary == "A":
# We are party A (primary) — fulfil locally for most requests
if request_type == "portability":
return DSARRoutingDecision.FULFIL_JOINTLY # Need partner data too
return DSARRoutingDecision.FULFIL_LOCALLY
else:
# We are party A (secondary) — route to party B
return DSARRoutingDecision.ROUTE_TO_PARTNER
def _notify_partner(self, record: dict) -> None:
"""Fire-and-forget notification with retry; log failure for manual follow-up."""
try:
httpx.post(
f"{self.partner_api_url}/dsar-intake",
json=record,
timeout=10,
)
except httpx.RequestError as exc:
# Log for manual follow-up — never silently drop a DSAR routing
import logging
logging.error("DSAR routing to partner failed: %s | record: %s", exc, record)
Breach Notification Coordination
Art.33 requires notifying the competent DPA within 72 hours of becoming aware of a breach. In a joint controller setup, both controllers may need to notify — or the arrangement must designate one as the notifying party with an obligation to inform the other immediately.
from datetime import datetime, timedelta
@dataclass
class BreachNotificationCoordination:
"""
Art.33 GDPR — breach notification coordination between joint controllers.
72-hour clock starts when EITHER party becomes aware.
"""
breach_detected_by: str # "A" or "B"
detected_at: datetime
notifying_party: str # Per Art.26 arrangement: "A" or "B"
dpa_notification_deadline: datetime = field(init=False)
partner_notification_deadline: datetime = field(init=False)
def __post_init__(self):
self.dpa_notification_deadline = self.detected_at + timedelta(hours=72)
# Internal partner notification: within 12h to give notifying party sufficient time
self.partner_notification_deadline = self.detected_at + timedelta(hours=12)
def is_dpa_deadline_at_risk(self, now: datetime) -> bool:
remaining = (self.dpa_notification_deadline - now).total_seconds() / 3600
return remaining < 24 # Alert if less than 24h remaining
Joint Controllership in Common SaaS Architectures
Scenario 1: Analytics Pixel / Tag Manager
You embed a third-party analytics SDK that sends event data to both your servers and the vendor's servers. The vendor independently processes this data for their own model training or benchmarking.
Joint control exists for: event collection and initial transmission
Sole control: your internal analytics dashboard; vendor's separate model training
Required: JCA for the collection phase; Art.13/14 notice must identify both controllers; either party can receive DSARs for the collection-phase data
Scenario 2: Co-Branded SaaS Product
Two companies jointly market a product. Users sign up through a shared interface; both companies can access user data for their respective service components.
Joint control exists for: onboarding data, shared user profile, joint communications
Sole control: each company's internal operations on their respective data extracts
Required: Full JCA; one contact point for data subjects; coordinated erasure procedure (erasure by one party must trigger erasure by both)
Scenario 3: Platform + ISV (Independent Software Vendor)
A PaaS provider (like sota.io) hosts an ISV's application. The ISV's customers' data is stored on PaaS infrastructure.
This is NOT joint control: The PaaS provider acts on the ISV's instructions — classic Art.28 processor relationship. The ISV is the sole controller. The PaaS provider does not determine the purpose of processing customer data.
Exception triggering Art.26: If the PaaS provider uses aggregated, identifiable customer data from the ISV's workloads for its own purposes (e.g., training internal models, generating benchmarks), joint control may arise for that specific secondary processing.
Scenario 4: Multi-Tenant Platform with Cross-Tenant Features
A platform enables tenant A to share data with tenant B (e.g., collaborative workspaces, shared customer databases). Once a data subject's data flows into a context where both tenants independently determine how it is used, Art.26 may apply between the tenants.
Engineering safeguard: Prevent unexpected cross-tenant joint control by requiring explicit JCA before enabling cross-tenant data sharing features.
// Gate cross-tenant data sharing behind JCA requirement
async function enableCrossTenantSharing(
tenantA: string,
tenantB: string,
sharingScope: string[],
): Promise<{ allowed: boolean; reason?: string }> {
const jca = await db.jointControllerArrangements.findFirst({
where: {
partyA: tenantA,
partyB: tenantB,
status: "signed",
processingScope: { hasSome: sharingScope },
},
});
if (!jca) {
return {
allowed: false,
reason:
"Cross-tenant data sharing requires a signed Joint Controller Arrangement. " +
"Contact your compliance team to establish one before enabling this feature.",
};
}
return { allowed: true };
}
EU Hosting Advantage Under Art.26
Joint controllership for data processed exclusively within the EU has significant structural advantages over cross-border joint control:
| Compliance Factor | EU-Only Joint Control | Cross-Border (EU + Non-EU) |
|---|---|---|
| Transfer mechanism | No SCCs needed between joint controllers | SCCs or BCRs required for non-EU party |
| Lead DPA (Art.60) | One LSA covers both parties if both have EU establishments | Complex jurisdiction analysis |
| Transfer Impact Assessment | Not required | Required for non-EU party |
| Art.48 government access | EU legal framework applies uniformly | Non-EU government access risk assessment required |
| Data subject rights routing | Single legal framework; consistent timelines | Different national law supplements may apply |
For SaaS operators choosing between an EU cloud provider and a US-headquartered provider as a joint analytics or infrastructure partner: the EU-only configuration eliminates the Chapter V transfer compliance layer entirely, reducing JCA complexity by approximately 40% (based on standard DPA template length analysis).
EDPB Guidance and Enforcement Cases
EDPB Guidelines 07/2020 on Joint Controllers
The EDPB's key clarifications:
- Symmetry is not required: One party can be more involved in determining purposes/means than the other. Joint control exists even with asymmetric involvement.
- Factual analysis overrides labels: Calling someone a "processor" in a contract does not make them one if they factually co-determine purposes.
- Temporal limits are possible: Joint control can be limited to specific processing phases (cf. Fashion ID).
- Individual liability: DPAs can impose fines on any or all joint controllers, proportionate to their involvement.
Enforcement Cases 2025–2026
IE-DPC-2025-11: Meta / Instagram Insights (€38.5M)
Meta and Instagram Business account holders were confirmed as joint controllers for Insights data. Meta's standard terms did not constitute a valid Art.26 arrangement because they failed to identify the specific responsibilities of business account operators. All business account operators were implicitly non-compliant. Remediation required Meta to issue updated Terms of Service with explicit JCA elements and expose a dedicated data subject contact point.
Developer takeaway: Platform T&Cs that embed JCA terms must explicitly allocate Art.13/14, DSAR, and breach notification responsibilities — not just reference "data controller" status.
DE-BfDI-2025-17: HR Software Consortium (€4.2M)
Three German HR software vendors operated a shared employee screening database under a data sharing agreement that classified each vendor as an independent controller. The BfDI found joint controllership because all three vendors contributed data to and drew from the same pool for the same purpose (employment background screening). No Art.26 arrangement existed; no contact point was disclosed to employees.
Developer takeaway: Shared databases where multiple parties contribute and consume data for a common purpose create joint controllership regardless of technical separation.
FR-CNIL-2025-22: Retail Analytics Platform (€2.8M)
A retail analytics SaaS embedded customer-facing analytics pixels on behalf of retailer clients. The SaaS vendor used aggregated (but re-identifiable) data for platform benchmarking. The CNIL found joint controllership for the benchmarking processing. No JCA existed; the retailer's privacy notices did not disclose the analytics vendor as a joint controller.
Developer takeaway: PaaS/SaaS providers that derive independent value from customer workload data become joint controllers for that secondary processing — even if they are processors for primary workload processing.
NL-AP-2026-01: B2B Data Marketplace (€6.1M)
A B2B data marketplace connected data buyers and sellers. The platform matched buyer queries with seller datasets and facilitated data transfers. The AP found the marketplace to be a joint controller with both buyers and sellers for the matching and transfer processing, not merely a processor facilitating transactions. No JCA existed for any of the ~800 buyer–seller pairs active on the platform.
Developer takeaway: Platforms that actively match, enrich, or route personal data between parties are likely joint controllers for the matching/routing operations — even if they do not retain the underlying data long-term.
IT-GdP-2025-14: Healthcare API Integration (€1.9M)
Two healthcare SaaS vendors integrated via API, sharing patient appointment data. The API integration agreement classified one vendor as processor of the other. The Garante found joint controllership because both vendors independently used appointment data to train their scheduling recommendation models. No Art.26 arrangement; privacy notices only disclosed one vendor.
Developer takeaway: API integrations where both sides derive independent model-training or analytics value from the exchanged data create joint controllership for those secondary uses.
Art.26 Compliance Checklist (25 Items)
Classification (5 items)
- JC-01 Mapped all data flows involving external parties (analytics vendors, partners, integrations, API consumers)
- JC-02 Applied the "jointly determine" test to each flow: does the other party independently determine purpose or means?
- JC-03 Documented classification decision (joint controller / processor / independent controller) with justification per flow
- JC-04 Reviewed platform T&Cs and integration agreements for implied processor classification that may actually be joint control
- JC-05 Phase-limited joint control identified where applicable (e.g., collection phase only per Fashion ID)
Arrangement (7 items)
- JC-06 Written Joint Controller Arrangement (JCA) exists for every confirmed joint controller relationship
- JC-07 JCA allocates Art.13/14 transparency obligations explicitly
- JC-08 JCA designates primary DSAR contact and response workflow between parties
- JC-09 JCA allocates Art.33/34 breach notification responsibility with 12-hour internal notification deadline
- JC-10 JCA designates which party signs Art.28 DPAs with sub-processors
- JC-11 JCA has defined scope, effective date, and review/termination provisions
- JC-12 Both parties have signed; signed copies stored in compliance repository
Transparency (5 items)
- JC-13 Privacy notice identifies all joint controllers by name and country (Art.26(2) + Art.13/14)
- JC-14 Privacy notice includes single contact point where data subjects can exercise rights against either controller
- JC-15 Essence of arrangement available to data subjects (not full commercial JCA — summary sufficient)
- JC-16 Privacy notice updated when new joint controller relationships are established
- JC-17 Cookie/tracking consent flows identify joint controllers for analytics/tracking processing
Rights Fulfilment (4 items)
- JC-18 DSAR system configured to accept and route requests for joint-controlled processing
- JC-19 Internal routing deadline set ≤5 days to preserve partner's response time within Art.12(3) 30-day window
- JC-20 Erasure requests trigger coordinated deletion across both joint controllers
- JC-21 Data portability requests (Art.20) coordinate export from both joint controllers where applicable
Monitoring (4 items)
- JC-22 New partnerships, integrations, and API relationships reviewed for joint control trigger before go-live
- JC-23 Annual review of existing JCAs against actual data flows (purpose creep check)
- JC-24 Incident response plan includes joint controller coordination procedure
- JC-25 Sub-processor changes communicated to joint controller partner per JCA terms
Summary
Art.26 imposes a clear structure on multi-party data processing: if you and another organisation jointly determine why and how personal data is processed, you are both controllers, you must formalise that relationship in writing, and you must expose a single contact point to data subjects who can enforce rights against either of you.
The engineering implications are concrete:
- Classification is factual, not contractual. Labelling a partner "processor" in a contract is insufficient — the factual processing relationship determines the legal classification.
- Platform architectures frequently create joint control — analytics pixels, co-branded products, data marketplaces, and cross-tenant sharing all require systematic joint controller analysis.
- Rights routing infrastructure is mandatory — receiving a DSAR for jointly controlled processing triggers your full Art.12(3) obligations regardless of which party the arrangement designates as primary.
- EU-only joint control eliminates Chapter V overhead — no SCCs, no TIA, no government access risk assessment between EU-established joint controllers.
GDPR Chapter IV continues with Art.27 (EU Representative obligations for non-EU controllers) and Art.28 (the Processor contract requirements that define the alternative to joint controllership for outsourced processing).
sota.io runs on EU infrastructure only — no data exits the EU. Joint controller arrangements with EU-based partners require no Standard Contractual Clauses, no Transfer Impact Assessments, and no Art.48 government access analysis. Start your EU-native deployment →