Public Document Reading

How to display documents on other sites for reading without formal acceptance

2024-01-15
documents reading api iframe integration

Guide: Public Document Reading (No Acceptance)

📖 Overview

This guide explains how to display documents (terms of use, policies, etc.) on other sites for reading, without the need for formal acceptance.

Important difference: - Reading: Just view the content (this guide) - Acceptance: Register formal acceptance with identity verification

---

🎯 When to Use

Use public reading when you want to: - Display terms of use on an "About" page of another site - Show privacy policy for reading - Embed legal documents on external sites - Allow consultation without mandatory acceptance

---

🚀 3 Implementation Methods

Option 1: Complete HTML Page (Best for direct links)

#### Available URLs: ` https://your-platform.com/documents/read/<slug>/ `

Example: ` https://legal-docs.com/documents/read/terms-of-use/ `

#### How to Use: 1. Configure public_acceptance_slug in the document 2. Enable public_acceptance_enabled = True 3. Share the link

#### Features: - ✅ Complete layout with header and footer - ✅ Button to accept (if needed) - ✅ Version and effective date information - ✅ Print button - ✅ Responsive

---

Option 2: Embedded Iframe (Best for embedding)

#### Available URLs: ` https://your-platform.com/documents/read/embedded/<UUID>/ `

Example: `html <!-- On your external site --> <div class="terms-container"> <iframe id="terms-iframe" src="https://legal-docs.com/documents/read/embedded/550e8400-e29b-41d4-a716-446655440000/" width="100%" height="600" frameborder="0" title="Terms of Use" style="border: 1px solid #e5e7eb; border-radius: 8px;" ></iframe> </div>

<script> // Auto-adjust height window.addEventListener('message', function(event) { if (event.data.type === 'resize_iframe') { document.getElementById('terms-iframe').style.height = event.data.height + 'px'; } }); </script> `

#### Configuration (Optional):

If you want to control which domains can embed:

`python from apps.agreements.models import Document, EmbeddedAcceptanceConfig

document = Document.objects.get(public_acceptance_slug="terms-of-use")

Create or update configuration

config, _ = EmbeddedAcceptanceConfig.objects.get_or_create( document=document, defaults={ 'enabled': True, 'allowed_domains': [ 'yoursite.com', 'www.yoursite.com', '*.yoursite.com', # Allows subdomains ], 'custom_css': ''' .title { color: #2563eb; } .content { font-size: 16px; } ''', 'hide_powered_by': True, } ) `

#### Features: - ✅ Minimalist layout (no header/footer) - ✅ Customizable via CSS - ✅ Allowed domain validation - ✅ Automatic height adjustment - ✅ No acceptance buttons

---

Option 3: REST API (JSON) (Best for total customization)

#### Available URLs: ` GET https://your-platform.com/api/documents/<slug>/ `

Example Request: `bash curl https://legal-docs.com/api/documents/terms-of-use/ `

Response: `json { "document_id": "550e8400-e29b-41d4-a716-446655440000", "name": "Terms of Use", "slug": "terms-of-use", "description": "Terms and conditions of platform use", "version": { "version_number": "2.0", "title": "Terms of Use - Version 2.0", "content_html": "<h1>Terms of Use</h1><p>...</p>", "content_plain": "Terms of Use\n\n...", "effective_date": "2024-01-01", "published_at": "2024-01-01T10:00:00Z" }, "urls": { "read": "https://...", "accept": "https://...", "embedded": "https://..." } } `

#### Implementation on Your Site:

HTML: `html <div id="terms-content"> <div class="loading">Loading terms of use...</div> </div> `

JavaScript: `javascript async function loadTerms() { try { const response = await fetch( 'https://legal-docs.com/api/documents/terms-of-use/' ); const data = await response.json(); // Render content document.getElementById('terms-content').innerHTML = ` <div class="terms-header"> <h1>${data.version.title}</h1> <p class="meta"> Version ${data.version.version_number} • Effective: ${new Date(data.version.effective_date).toLocaleDateString('en-US')} </p> </div> <div class="terms-body"> ${data.version.content_html} </div> <div class="terms-footer"> <a href="${data.urls.accept}" class="btn-accept"> Accept Terms of Use </a> </div> `; } catch (error) { console.error('Error loading terms:', error); document.getElementById('terms-content').innerHTML = '<p class="error">Error loading terms of use.</p>'; } }

// Load when page loads loadTerms(); `

React/Next.js: `jsx 'use client';

import { useEffect, useState } from 'react';

export default function TermsOfService() { const [terms, setTerms] = useState(null); const [loading, setLoading] = useState(true);

useEffect(() => { fetch('https://legal-docs.com/api/documents/terms-of-use/') .then(res => res.json()) .then(data => { setTerms(data); setLoading(false); }) .catch(err => { console.error(err); setLoading(false); }); }, []);

if (loading) return <div>Loading...</div>; if (!terms) return <div>Error loading terms</div>;

return ( <div className="terms-container"> <h1>{terms.version.title}</h1> <div className="meta"> Version {terms.version.version_number} • Effective: {new Date(terms.version.effective_date).toLocaleDateString('en-US')} </div> <div className="content" dangerouslySetInnerHTML={{ __html: terms.version.content_html }} /> <a href={terms.urls.accept} className="btn-accept"> Accept Terms </a> </div> ); } `

#### Features: - ✅ Total design customization - ✅ CORS enabled (Access-Control-Allow-Origin: *) - ✅ HTTP cache (1 hour) - ✅ HTML and plain text available - ✅ Links for acceptance and embedded included

---

📊 Option Comparison

| Aspect | HTML Page | Iframe | REST API | |--------|-----------|--------|----------| | Implementation | ⭐⭐⭐ Very easy | ⭐⭐ Easy | ⭐ Requires code | | Customization | ❌ Limited | ⚠️ CSS only | ✅ Total | | Maintenance | ✅ Zero | ✅ Zero | ⚠️ You control | | Updates | ✅ Automatic | ✅ Automatic | ⚠️ Depends on cache | | Performance | ⭐⭐ Good | ⭐⭐ Good | ⭐⭐⭐ Excellent | | SEO | ✅ Indexable | ❌ Not indexed | ✅ You control | | Mobile | ✅ Responsive | ✅ Responsive | ✅ You control |

---

🔧 Step-by-Step Configuration

1. In Django Admin:

`python

Via shell or admin

from apps.agreements.models import Document

1. Configure document

document = Document.objects.get(name="Terms of Use") document.public_acceptance_slug = "terms-of-use" document.public_acceptance_enabled = True document.is_active = True document.save()

2. Make sure you have an active version

version = document.get_active_version() print(f"Active version: {version.version}")

3. Get URLs

print(f"Read URL: /documents/read/{document.public_acceptance_slug}/") print(f"Embedded URL: /documents/read/embedded/{document.document_key}/") print(f"API URL: /api/documents/{document.public_acceptance_slug}/") `

2. (Optional) Configure Embedding with Restricted Domains:

`python from apps.agreements.models import EmbeddedAcceptanceConfig

config = EmbeddedAcceptanceConfig.objects.create( document=document, enabled=True, allowed_domains=[ 'yoursite.com', 'www.yoursite.com', 'staging.yoursite.com', ], custom_css=''' .title { color: #1a56db; font-family: 'Inter', sans-serif; } .content { font-size: 15px; line-height: 1.8; } ''', hide_powered_by=True, ) `

3. Test URLs:

HTML Page: ` http://localhost:8000/documents/read/terms-of-use/ `

Iframe: ` http://localhost:8000/documents/read/embedded/550e8400-e29b-41d4-a716-446655440000/ `

API: `bash curl http://localhost:8000/api/documents/terms-of-use/ `

---

🎨 CSS Customization Examples

Modern Style (for Iframe):

`css .title { font-family: 'Inter', -apple-system, sans-serif; font-size: 28px; font-weight: 700; color: #111827; letter-spacing: -0.02em; }

.content { font-size: 16px; line-height: 1.75; color: #374151; }

.content h2 { color: #1f2937; font-size: 20px; font-weight: 600; margin-top: 2em; border-bottom: 2px solid #e5e7eb; padding-bottom: 0.5em; } `

---

🔒 Security

CORS (API):

- API returns Access-Control-Allow-Origin: * - Allows access from any domain - No authentication required (public content)

Iframe:

- CSP headers configured automatically - Allowed domain validation (if configured) - No cookies or sessions required

---

💡 Use Cases

1. Institutional Site:

`html <!-- On https://mysite.com/terms --> <iframe src="https://legal-docs.com/documents/read/embedded/UUID/" width="100%" height="800"></iframe> `

2. SPA/React App:

`jsx import TermsAPI from './components/TermsAPI';

function TermsPage() { return <TermsAPI slug="terms-of-use" />; } `

3. Direct Link:

`html <a href="https://legal-docs.com/documents/read/terms-of-use/" target="_blank"> Read our Terms of Use </a> `

---

🆚 Comparison: Reading vs Acceptance

| Feature | Reading | Acceptance | |---------|---------|------------| | Form | ❌ No | ✅ Yes | | Email Verification | ❌ No | ✅ Yes (Magic Link/OTP) | | Database Record | ❌ No | ✅ Yes | | Audit | ❌ No | ✅ Complete | | Certificate | ❌ No | ✅ Yes | | Use | Consultation | Legal Acceptance |

---

📱 Responsiveness

All 3 options are mobile-friendly: - HTML Page: Responsive with Tailwind CSS - Iframe: Auto-adjusts height - API: You control the design

---

⚡ Performance

Cache:

- API: HTTP cache of 1 hour (Cache-Control: public, max-age=3600) - HTML/Iframe: Browser-controlled cache

---

🐛 Troubleshooting

Iframe doesn't load:

1. Check allowed_domains in configuration 2. Test with allowed_domains = [] (permissive mode) 3. Check browser console (CORS/CSP)

API returns 404:

1. Check public_acceptance_enabled = True 2. Check is_active = True 3. Check if active version exists

Content doesn't update:

1. Clear browser cache 2. Check if version is published 3. Force refresh: Ctrl+Shift+R

---

🎓 Next Steps

- [ ] Configure your documents - [ ] Choose method (HTML, Iframe or API) - [ ] Implement on your site - [ ] (Optional) Configure allowed domains - [ ] (Optional) Customize CSS - [ ] Test in production

---

💬 Questions?

If you need formal acceptance (with identity verification), use: - /acceptance/<slug>/ - Public acceptance form - /embedded/<uuid>/ - Acceptance via iframe (with form)

This guide is for reading only, without acceptance.

Was this page helpful?