Why European Compliance Belongs on the Client Side
When building B2B applications for European clients, data privacy isn't just a feature—it is a legal requirement. With the rollout of mandatory electronic invoicing across the EU (such as Belgium’s Jan 2026 mandate and France’s Sep 2026 reform) alongside strict GDPR enforcement, developers are faced with a dilemma:
How do you validate sensitive financial data (banking details, invoice totals, VAT numbers) without introducing server-side data liability?
The answer is 100% Client-Side Execution. By shifting parsing, XML serialization, and validation algorithms entirely to the browser in Next.js 14, you completely eliminate server logging, database retention, and GDPR payload overhead.
Here is an architectural look at how we built a zero-server EU compliance utility suite on FreeToolForge.
1. Generating Peppol BIS Billing 3.0 UBL 2.1 XML in the Browser
Peppol (Pan-European Public Procurement OnLine) requires invoice data to strictly match the UBL 2.1 XML schema and EN16931 European standards. Sending raw financial payloads to a backend API introduces data security risks.
To solve this, our client component builds the XML document object model locally before rendering:
typescript
// Client-side XML Escaping & Payload Construction
function escapeXml(str: string): string {
return str.replace(/[<>&'"]/g, (c) => {
switch (c) {
case '<': return '<';
case '>': return '>';
case '&': return '&';
case '\'': return ''';
case '"': return '"';
default: return c;
}
});
}
// Generating compliant UBL 2.1 XML without server roundtrips
export function generatePeppolXml(invoiceData: InvoicePayload): string {
return `<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID>
<cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>
<cbc:ID>${escapeXml(invoiceData.id)}</cbc:ID>
<cbc:IssueDate>${invoiceData.issueDate}</cbc:IssueDate>
<cbc:DocumentCurrencyCode>${invoiceData.currency}</cbc:DocumentCurrencyCode>
<!-- Fully generated client-side -->
</Invoice>`;
}
Top comments (0)