An ADK Java agent spreads personal data further than a classic web app. Each turn writes session events, may add long-term memory, sends text to a model provider and passes fields to tools, while traces copy all of it. If your users are in the European Union and in India, two laws govern those flows: the GDPR and India's Digital Personal Data Protection Act, 2023 (DPDP Act) with the DPDP Rules, 2025.
This article maps both regimes onto the parts of an ADK Java application you can change: plugins, tools, stores and logs. It is engineering guidance, not legal advice, so have counsel confirm the legal decisions.
Two regimes, one agent
Start with vocabulary, because the two laws name the same roles differently, and contracts and notices must use the right words.
| Concept | GDPR | DPDP Act 2023 | What it means for the agent |
|---|---|---|---|
| Person the data is about | Data subject | Data Principal | The end user, and anyone named in their messages or uploads |
| Decides purpose and means | Controller | Data Fiduciary | Your company, which owns the agent |
| Processes on instructions | Processor | Data Processor | Model provider, vector database, hosted tool APIs |
| Grounds to process | Six lawful bases (Art. 6) | Consent, or a listed legitimate use (s. 7) | DPDP has no contract or legitimate-interest ground |
| Children | Art. 8: 16 by default, member states may lower to 13 | Under 18, verifiable parental consent | Age gate before the first model call |
The grounds row changes the most code. Under GDPR a support agent can often rely on contract to look up orders and on legitimate interests for fraud checks. The DPDP Act offers only consent (section 6) or a legitimate use listed in section 7, such as data volunteered for a specified purpose, disclosures a law requires to the State, court orders, medical emergencies and employment. There is no general legal-obligation ground. A GDPR record of processing copied into India lists grounds that do not exist there. So each tool needs a purpose, and each purpose a ground per regime.
Timing matters too. The DPDP Rules were notified on 13 November 2025 and commence in phases: Board provisions at once, consent manager registration after twelve months, and the core obligations (notice, consent, safeguards, breach reporting, retention, erasure) after eighteen months, around May 2027. As of October 2026 they are not yet enforceable, which is why to build for them now.
Where personal data lives in an ADK Java app
List the stores before writing any policy. The SessionService holds events: messages, model responses, function calls and results. The memory service holds facts extracted across sessions, and the artifact service holds uploads such as ID scans. The model provider receives the full request on every call, tools receive their arguments, and logs and traces often hold the most complete copy of all.
Two controls follow. First, minimise what enters. Redaction in onUserMessageCallback and afterToolCallback keeps raw identifiers out of every downstream store at once; PII redaction in ADK Java covers which hook runs before persistence. Second, key every store by a stable subject token so that access and erasure requests become queries rather than investigations.
A purpose gate as a plugin
Agents break purpose limitation most often because the model chooses which tools to call. A user who consented to order support should not have their credit record pulled because the model thought it would help. Prompts cannot enforce that; a plugin on the runner can, because it sees every tool call before the tool runs.
A static map gives each tool a purpose. A consent ledger records, per user, which purposes they agreed to, under which notice version, and any withdrawal. A beforeToolCallback denies calls without a valid ground. A non-empty return becomes the tool's result and the tool is skipped, so the model receives a refusal it can explain.
public final class PurposeGatePlugin extends BasePlugin {
private final Map<String, String> toolPurpose; // "credit_check" -> "lending_eligibility"
private final ConsentLedger ledger; // backed by a table, not by session state
private final AuditSink audit;
public PurposeGatePlugin(Map<String, String> toolPurpose, ConsentLedger ledger, AuditSink audit) {
super("purpose_gate");
this.toolPurpose = toolPurpose;
this.ledger = ledger;
this.audit = audit;
}
@Override
public Maybe<Map<String, Object>> beforeToolCallback(
BaseTool tool, Map<String, Object> args, ToolContext toolContext) {
String purpose = toolPurpose.get(tool.name());
if (purpose == null) return Maybe.just(deny("tool has no declared purpose")); // fail closed
String user = toolContext.userId();
Ground g = ledger.groundFor(user, purpose); // CONSENT, LEGITIMATE_USE, CONTRACT, NONE
boolean ok = g.validFor(ledger.regimeOf(user)); // CONTRACT is never valid for DPDP
audit.record(user, tool.name(), purpose, ok ? "ALLOWED" : "DENIED", g);
return ok ? Maybe.empty() : Maybe.just(deny("no valid ground for " + purpose));
}
private static Map<String, Object> deny(String why) {
return Map.of("status", "blocked_by_policy", "reason", why,
"instruction", "Tell the user this needs their permission; do not retry.");
}
}Register it once with Runner.builder().plugins(new PurposeGatePlugin(...)) so later sub-agents inherit it. It fails closed, so no tool ships without a purpose. The ledger lives in your database, not session state, because users can withdraw from another channel mid-session. The audit record, keyed by subject token, is what you show a regulator; audit logging in ADK Java shows a tamper-evident version.
The consent behind the gate must be valid. DPDP section 6 requires consent that is free, specific, informed, unconditional and unambiguous, by clear affirmative action after an itemised notice, available in English or an Eighth Schedule language. "By continuing you agree" fails both laws.
Data subject and Data Principal rights
Both laws give people rights over their data; the agent must be able to answer them without an engineer reading tables by hand.
| Right | GDPR | DPDP | Implementation in the agent |
|---|---|---|---|
| Access | Art. 15 | s. 11, summary plus who it was shared with | Subject index query across all stores |
| Correction | Art. 16 | s. 12 | Fix the source; re-derive or delete derived memory |
| Erasure | Art. 17 | s. 12, unless the purpose or a law needs it | Delete across stores, tombstone backups |
| Portability, objection, automated decisions | Art. 20, 21, 22 | No equivalent | Keep for EU users |
| Grievance, nomination | Complaint to authority | s. 13 and s. 14 | Grievance tool with an SLA; nominee field |
Erasure is where agents differ most. A fact the memory service extracted is personal data even after the conversation is deleted, so the subject index must record derived records too. The right to be forgotten in ADK Java walks the deletion path. Add one rule: the deletion job also revokes the ledger entries, so a later login cannot quietly resume a withdrawn purpose.
Retention that satisfies both laws
Storage limitation conflicts with itself. Both laws say keep data no longer than the purpose needs (DPDP section 8(7)). The Rules add numbers: Third Schedule e-commerce, gaming and social media fiduciaries erase data three years after the person last engaged, warning them 48 hours before; and logs must be kept at least one year for security, longer if another law (often AML or tax) says so.
Separate content from evidence. Conversation content follows the purpose clock. Security logs keep subject tokens, timestamps, tool names and decisions, never message text. A daily sweeper:
-- erase content whose purpose clock expired, unless a legal hold applies
DELETE FROM session_event e USING purpose_clock pc
WHERE e.subject_token = pc.subject_token AND e.purpose = pc.purpose
AND pc.expires_at < now() AND NOT pc.legal_hold;
-- logs hold evidence, not content; 400 days is a margin over one year
DELETE FROM security_log WHERE created_at < now() - INTERVAL '400 days' AND NOT legal_hold;A second job queues the 48-hour notices. Make the legal hold a column compliance can set without a deploy.
Transfers and breach clocks
A prompt sent to a model hosted abroad is a cross-border transfer. GDPR Chapter V needs an adequacy decision, standard contractual clauses with a transfer risk assessment, or another listed mechanism. DPDP section 16 takes the opposite default: transfers are allowed except to countries the government restricts by notification. Sector rules, such as payment data storage requirements, can still force localisation. In ADK Java this is routing: pick the model endpoint and storage region per user regime, and record the region in the subject index.
Breach rules diverge too. GDPR Article 33 requires notifying the supervisory authority within 72 hours unless the breach is unlikely to cause risk, and Article 34 adds individuals when risk is high. DPDP section 8(6) has no risk threshold: the Board and each affected Data Principal must be told of any breach. The Rules require that intimation without delay, then a detailed report to the Board within 72 hours. Penalties reach 250 crore rupees for failed safeguards; GDPR fines reach 20 million euros or 4 percent of worldwide turnover.
So for Indian users even a prompt injection that exposes one other customer's order triggers individual notices. The subject index must answer "whose data was in this session" in minutes, from the audit records the purpose gate already writes.
Worked example: one agent, two markets
Consider a bill-payment company in Bengaluru with an ADK Java support agent. It serves Indian customers and, through a subsidiary, customers in Ireland. The agent has four tools: order_status, refund, kyc_document_check and offer_recommendation.
Purposes are declared as support, refund processing, regulatory KYC and marketing. For Irish users the grounds are contract for support and refunds, legal obligation for KYC and consent for marketing. For Indian users the ledger holds a consent for support and refunds collected at sign-up. KYC needs its own explicit consent or the section 7(a) voluntarily-provided use; only reports to the FIU rest on section 7(d). Counsel should confirm both. Marketing has a separate, unticked toggle. When an Indian user who declined marketing asks "any cashback for me?", the model calls offer_recommendation. The gate returns blocked_by_policy, and the agent replies that offers need a marketing permission the user can grant in settings.
A customer uploads a masked ID image for KYC. The artifact is stored under the KYC purpose with an AML-driven retention period, not the support clock. When the user later asks for erasure, the job removes sessions, memory facts and marketing profiles, keeps the KYC artifact under legal hold, and tells the user which law requires it, which both regimes allow.
Failure modes
These are the failures that show up in audits of real agents.
- Grounds copied across regimes. A record of processing lists legitimate interest for Indian users. Fix it by recording a ground per purpose per regime and making the gate check it.
- Consent in session state. Withdrawal through the app settings never reaches a live session. The ledger must be read on every gated call, with a short cache at most.
- Logs as the shadow copy. Full prompts in traces outlive every erasure. Log tokens and decisions, and send content to a separate store with the content retention clock.
- Derived memory forgotten. Erasure deletes the conversation but not the facts memory extracted from it. Index derived records by subject token at write time.
- Children treated as adults. A DPDP user aged 16 can use the product under a GDPR-style age gate. DPDP needs verifiable parental consent under 18 and bars behavioural monitoring and targeted advertising aimed at children.
- Breach clock started late. Teams wait for a risk assessment before notifying Indian users. Under DPDP the duty does not depend on risk; start the intimation workflow at awareness.
Trade-offs
The main trade-off is one global policy versus per-regime behaviour. The stricter rule everywhere, such as consent for every purpose, is simpler to test but removes legitimate options in Europe and adds prompts users ignore. Per-regime routing keeps options but doubles the test matrix. Most teams use one ledger and one gate, with regime-specific grounds tables and notices.
A second trade-off is redaction versus usefulness. Aggressive redaction protects every store but breaks tools that need the identifier. Look records up by authenticated user ID instead of passing identifiers through the model, so the model rarely needs to see the value at all.
What to do next
To make an ADK Java agent ready for both regimes:
- Inventory every store and processor the agent touches, including logs, traces and backups, and record each one's region.
- Declare a purpose for every tool, and a ground per purpose per regime; remove contract and legitimate interest from the DPDP column.
- Build the consent ledger outside session state and register a purpose gate plugin that fails closed.
- Add inbound and tool-result redaction before persistence, and key every store by a subject token.
- Separate content retention from security-log retention, and run a daily sweeper with legal holds and 48-hour notices where the Third Schedule applies.
- Route model calls by regime, and record transfer mechanisms for EU subjects.
- Write one breach runbook with both clocks. Run a tabletop exercise in which a prompt injection exposes one other customer's record.
- Track the DPDP commencement dates and finish this work before the core obligations start in 2027. For the GDPR side of the same design, read GDPR for LLM applications.