OPEN-SOURCE POLICY-AS-CODE

Framework for building privacy-first applications

v0.0.23 · GPL-3.0

BLOG.md / astro

Ship a Privacy Policy with Your Astro Site

Use the OpenPolicy Astro integration to generate a legally-structured privacy policy at build time — no Google Docs, no copy-paste.

March 5, 2026

Most Astro sites need a privacy policy before they launch. The usual approach: grab a template from the internet, paste it into a static page, and forget about it until a lawyer asks why it still says “Company Name Here.”

OpenPolicy treats your policies like code. You define them as TypeScript objects, and the Astro integration compiles them to Markdown at build time — in sync with every deploy.

Install

npx astro add @openpolicy/astro
bun add @openpolicy/sdk

astro add installs the package and automatically updates astro.config.mjs. If you prefer to wire it up manually:

bun add -D @openpolicy/astro @openpolicy/vite

Add the integration to astro.config.mjs

import { defineConfig } from "astro/config";
import { openPolicy } from "@openpolicy/astro";

export default defineConfig({
  integrations: [
    openPolicy({
      formats: ["markdown"],
      outDir: "src/generated/policies",
    }),
  ],
});

On the first bun run dev, if the config file doesn’t exist yet, the plugin scaffolds it automatically. Edit the generated file and save — the plugin watches for changes and regenerates.

Define your policies

Create a single openpolicy.ts at the root of your project. The unified defineConfig() lets you define all policies in one file with a shared company block:

// openpolicy.ts
import { defineConfig } from "@openpolicy/sdk";

export default defineConfig({
  company: {
    name: "Acme",
    legalName: "Acme, Inc.",
    address: "123 Main St, San Francisco, CA 94105",
    contact: "privacy@acme.com",
  },
  effectiveDate: "2026-03-05",
  jurisdictions: ["us", "eu"],
  dataCollected: {
    "Account information": ["Email address", "Display name"],
    "Usage data": ["Pages visited", "Session duration"],
  },
  legalBasis: ["legitimate_interests", "consent"],
  retention: {
    "Account data": "Until account deletion",
    "Analytics data": "13 months",
  },
  thirdParties: [
    { name: "Vercel", purpose: "Hosting and edge delivery" },
    { name: "Plausible", purpose: "Privacy-friendly analytics" },
  ],
  cookies: {
    essential: true,
    analytics: true,
    marketing: false,
  },
});

What gets generated

After the next build (or on save in dev), the plugin writes:

src/generated/policies/
  privacy-policy.md

Because the files land inside src/, Astro can import them directly as Markdown components.

Render on a dedicated page

---
// src/pages/privacy.astro
import { Content } from "../../generated/policies/privacy-policy.md";
---
<div class="prose prose-gray max-w-none">
  <Content />
</div>

Astro compiles the Markdown to HTML at build time, so there’s no client-side rendering overhead. The prose class (from Tailwind Typography) handles all the heading, list, and paragraph styles.

Add .gitignore entries so the generated files aren’t checked in:

# .gitignore
src/generated/

Why this is better than a static page

  • Type-safe. Every field is checked by TypeScript. You can’t ship a policy with a missing contact email.
  • Structured. Each section is generated from your actual config — no stale placeholder text.
  • Version-controlled. The config lives in your repo. git blame shows you when and why anything changed.
  • Jurisdiction-aware. Set jurisdictions: ["eu"] and GDPR-required sections (right to erasure, data transfers, DPA contact) are included automatically.

The generated Markdown includes all required sections for the jurisdictions you specify. You own the config; OpenPolicy handles the legal structure.