Privacy-preserving email marketplace with x402 payments and user control.
DataGuard is a revolutionary browser extension that transforms your email inbox into a privacy-preserving data marketplace where you get paid for controlled access to your email data through the x402 payment protocol. Instead of having your data extracted without permission, DataGuard puts you in complete control of who accesses what data and ensures you're compensated for it.
The Problem: Currently, AI agents and third-party applications extract email data without user consent or compensation, creating privacy violations and data exploitation.
The Solution: DataGuard intercepts data requests, applies user-defined privacy policies, requires payment through x402 protocol, and returns only filtered, redacted data with cryptographic proofs - all while ensuring users are paid for their data.
The project includes a comprehensive demo environment:
https://data-gaurd.vercel.app
with 21 realistic emailsDataGuard represents a paradigm shift from data extraction to data compensation, empowering users to monetise their personal data while maintaining privacy and control. It's built for the ETHGlobal New Delhi 2025 hackathon and demonstrates a complete end-to-end privacy-preserving data marketplace.
DataGuard is built as a multi-component system with a Chrome extension as the core, a separate mail demo service, and sophisticated payment processing - all designed to work together seamlessly.
// Both popup.ts and extension-page.ts are nearly identical
// This allows the same functionality in both popup and full-page modes
class DataGuardPopup { /* 660 lines */ }
class DataGuardExtensionPage { /* 660 lines */ }
Why this hack? Chrome extension popups have size limitations, so we created a full-page version accessible via chrome.action.onClicked
. The code duplication was intentional for rapid development.
// Injects a global API that websites can call
window.DataGuardAPI = {
requestEmailData: (predicate, callback) => {
// Intercepts and processes requests
}
};
The clever part: Instead of trying to intercept all network requests (which would require broad permissions), we inject a controlled API that websites can use, making the extension more privacy-friendly.
// All x402 payments are currently simulated for demo purposes
async function simulateFacilitatorPayment(paymentRequest: X402PaymentRequest): Promise<X402PaymentResponse> {
await new Promise(resolve => setTimeout(resolve, 1000)); // Simulate network delay
return {
success: true,
paymentProof: `proof_${paymentRequest.requestId}_${Date.now()}`,
transactionHash: `0x${Math.random().toString(16).substr(2, 64)}`
};
}
Why simulated? Real x402 integration requires complex blockchain setup. The simulation maintains the exact API contract while allowing full demo functionality.
// Graceful degradation when mail service is unavailable
async function fetchEmailData(predicate: EmailPredicate): Promise<EmailData[]> {
try {
const response = await fetch('https://data-gaurd.vercel.app/api/emails');
return await response.json();
} catch (error) {
console.log('Using mock data as fallback');
return getMockEmailData(predicate); // Always works offline
}
}
The hack: Built-in fallback ensures the extension always works, even if the external service is down.
private calculateDynamicPrice(request: NegotiationRequest, basePrice: number): number {
let finalPrice = basePrice;
// Demand multiplier based on recent requests
const requestCount = this.getRecentRequestCount(request.predicateType);
const demandMultiplier = Math.min(1 + (requestCount * 0.1), 2.0); // Max 2x
// Privacy multiplier
if (request.requestedData.includeBodies) finalPrice *= 1.5;
if (request.requestedData.includePersonalInfo) finalPrice *= 1.3;
// Volume multiplier
const volumeMultiplier = 1 + ((request.requestedData.maxEmails - 10) / 10) * 0.2;
finalPrice *= Math.min(volumeMultiplier, 2.0);
return Math.round(finalPrice * 1000) / 1000;
}
The innovation: Real-time pricing that adapts to demand, privacy sensitivity, and volume - creating a true marketplace dynamic.
{
"scripts": {
"build": "tsc && yarn copy-assets",
"copy-assets": "cp -r src/assets/* dist/ && cp manifest.json dist/ && cp src/ui/popup/popup.html dist/ && cp src/ui/popup/popup.css dist/"
}
}
The hack: Manual asset copying instead of webpack because Chrome extensions have specific file structure requirements.
// vercel.json
{
"rewrites": [
{
"source": "/api/emails",
"destination": "/api/index"
}
]
}
Clever routing: Uses Vercel's rewrite rules to create clean API endpoints without complex routing logic.
// tsconfig.json
{
"module": "none", // No module system - Chrome extensions don't support ES modules
"target": "ES2020" // Modern JS features
}
Why "module": "none"? Chrome extensions can't use ES modules in content scripts, so we compile to plain JavaScript with proper type checking.
// 21 carefully crafted emails with realistic senders
const sampleEmails = [
{ from: '[email protected]', subject: 'Your package has been delivered', type: 'delivery' },
{ from: '[email protected]', subject: 'Weekly Tech News', type: 'subscription' },
{ from: '[email protected]', subject: 'Receipt for your purchase', type: 'purchase' }
];
The attention to detail: Each email is realistic and properly categorized, making the demo feel authentic.
// Multiple timeout strategies for different scenarios
setTimeout(() => {
if (this.mailServiceStatus?.textContent === 'Connecting...') {
this.mailServiceStatus.textContent = 'Timeout';
}
}, 15000);
// And also:
const timeoutId = setTimeout(() => controller.abort(), 8000);
Why multiple timeouts? Different operations need different timeout strategies - UI feedback vs network requests.
private sendMessageToBackground(message: any): Promise<any> {
return new Promise((resolve, reject) => {
chrome.runtime.sendMessage(message, (response) => {
if (chrome.runtime.lastError) {
reject(new Error(chrome.runtime.lastError.message));
} else {
resolve(response);
}
});
});
}
The hack: Chrome's callback-based APIs are wrapped in Promises for cleaner async/await code.
// Injects a subtle indicator when DataGuard is active
const indicator = document.createElement('div');
indicator.innerHTML = '🛡️';
indicator.style.cssText = 'position:fixed;top:10px;right:10px;z-index:999999;font-size:16px;opacity:0.7;';
document.body.appendChild(indicator);
User experience hack: Provides visual feedback that the extension is protecting the user's data.
# Simple commands for multi-component development
extension-build:
cd extension && yarn build
demo-start:
cd mail-demo && yarn start
Why Just instead of npm scripts? Cross-directory commands are cleaner with Just, and it handles the multi-component nature better.
This architecture demonstrates how to build a complex privacy-preserving system using modern web technologies while maintaining simplicity and reliability. The "hacky" solutions were often intentional trade-offs that prioritised functionality and user experience over perfect architectural purity.