Skip to main content
Document metadata stores key-value properties that describe the document itself, such as title, author, creation date, or processing status. This is distinct from content node features which are attached to specific nodes in the document tree.

Setting Metadata

Individual Values

from kodexa_document import Document

with Document() as doc:
    # Set individual metadata values
    doc.set_metadata("title", "Invoice #12345")
    doc.set_metadata("author", "Accounting System")
    doc.set_metadata("created_date", "2024-01-15")
    doc.set_metadata("document_type", "invoice")

    # Values can be strings, numbers, booleans, lists, or dicts
    doc.set_metadata("page_count", 3)
    doc.set_metadata("processed", True)
    doc.set_metadata("tags", ["financial", "q1-2024", "priority"])
    doc.set_metadata("source", {
        "system": "ERP",
        "id": "DOC-2024-001"
    })
import { Kodexa } from '@kodexa-ai/document-wasm-ts';

async function setMetadata() {
  await Kodexa.init();
  const doc = await Kodexa.createDocument();

  try {
    // Set individual metadata values
    await doc.setMetadataValue('title', 'Invoice #12345');
    await doc.setMetadataValue('author', 'Accounting System');
    await doc.setMetadataValue('createdDate', '2024-01-15');
    await doc.setMetadataValue('documentType', 'invoice');

    // Values can be strings, numbers, booleans, arrays, or objects
    await doc.setMetadataValue('pageCount', 3);
    await doc.setMetadataValue('processed', true);
    await doc.setMetadataValue('tags', ['financial', 'q1-2024', 'priority']);
    await doc.setMetadataValue('source', {
      system: 'ERP',
      id: 'DOC-2024-001'
    });
  } finally {
    doc.dispose();
  }
}

Bulk Metadata

with Document(metadata={
    "title": "Invoice #12345",
    "author": "Accounting System",
    "created_date": "2024-01-15"
}) as doc:
    # Metadata is set at creation time
    print(f"Title: {doc.get_metadata('title')}")

# Or replace all metadata at once
with Document() as doc:
    doc.metadata = {
        "title": "Updated Title",
        "version": "2.0"
    }
async function setBulkMetadata() {
  await Kodexa.init();
  const doc = await Kodexa.createDocument();

  try {
    // Set multiple values at once
    await doc.setMetadata({
      title: 'Invoice #12345',
      author: 'Accounting System',
      createdDate: '2024-01-15'
    });
  } finally {
    doc.dispose();
  }
}

Reading Metadata

Individual Values

with Document.from_kddb("document.kddb") as doc:
    # Get specific metadata values
    title = doc.get_metadata("title")
    author = doc.get_metadata("author")

    print(f"Title: {title}")
    print(f"Author: {author}")

    # Non-existent keys return None
    missing = doc.get_metadata("nonexistent")
    print(f"Missing: {missing}")  # None
async function readMetadata() {
  await Kodexa.init();
  const doc = await Kodexa.fromBlob(kddbBlob);

  try {
    // Get specific metadata values
    const title = await doc.getMetadataValue('title');
    const author = await doc.getMetadataValue('author');

    console.log(`Title: ${title}`);
    console.log(`Author: ${author}`);

    // Non-existent keys return null/undefined
    const missing = await doc.getMetadataValue('nonexistent');
    console.log(`Missing: ${missing}`);
  } finally {
    doc.dispose();
  }
}

All Metadata

with Document.from_kddb("document.kddb") as doc:
    # Access all metadata as a dict-like object
    metadata = doc.metadata

    # Iterate through all metadata
    for key in metadata:
        print(f"{key}: {metadata[key]}")

    # Check if key exists
    if "title" in metadata:
        print(f"Has title: {metadata['title']}")
async function readAllMetadata() {
  await Kodexa.init();
  const doc = await Kodexa.fromBlob(kddbBlob);

  try {
    // Get all metadata as an object
    const metadata = await doc.getMetadata();

    // Iterate through all metadata
    for (const [key, value] of Object.entries(metadata)) {
      console.log(`${key}: ${value}`);
    }

    // Check if key exists
    if (metadata.title) {
      console.log(`Has title: ${metadata.title}`);
    }
  } finally {
    doc.dispose();
  }
}

Document Labels

Labels provide a simple way to categorize documents with string tags:
with Document() as doc:
    # Add labels
    doc.add_label("invoice")
    doc.add_label("financial")
    doc.add_label("q1-2024")
    doc.add_label("processed")

    # Get all labels
    labels = doc.labels
    print(f"Labels: {labels}")  # ['invoice', 'financial', 'q1-2024', 'processed']

    # Check for specific label
    if "invoice" in doc.labels:
        print("This is an invoice")
async function workWithLabels() {
  await Kodexa.init();
  const doc = await Kodexa.createDocument();

  try {
    // Labels are typically stored in metadata
    await doc.setMetadataValue('labels', ['invoice', 'financial', 'q1-2024']);

    // Read labels
    const labels = await doc.getMetadataValue('labels') || [];
    console.log(`Labels: ${labels}`);

    // Check for specific label
    if (labels.includes('invoice')) {
      console.log('This is an invoice');
    }
  } finally {
    doc.dispose();
  }
}

Document Identity

Every document has a unique identifier and version:
with Document() as doc:
    # UUID is auto-generated
    print(f"Document UUID: {doc.uuid}")

    # Version tracks document changes
    print(f"Version: {doc.version}")
async function getDocumentIdentity() {
  await Kodexa.init();
  const doc = await Kodexa.createDocument();

  try {
    // UUID is auto-generated
    const metadata = await doc.getMetadata();
    console.log(`Document UUID: ${metadata.uuid}`);
  } finally {
    doc.dispose();
  }
}

Source Metadata

Track the original source of the document:
with Document(source={
    "connector": "file-upload",
    "original_filename": "invoice_scan.pdf",
    "mime_type": "application/pdf",
    "size": 125000
}) as doc:
    # Access source information
    source = doc.source
    print(f"Original file: {source.original_filename}")
    print(f"MIME type: {source.mime_type}")
async function trackSource() {
  await Kodexa.init();
  const doc = await Kodexa.createDocument();

  try {
    // Store source information in metadata
    await doc.setMetadataValue('source', {
      connector: 'file-upload',
      originalFilename: 'invoice_scan.pdf',
      mimeType: 'application/pdf',
      size: 125000
    });

    const source = await doc.getMetadataValue('source');
    console.log(`Original file: ${source.originalFilename}`);
  } finally {
    doc.dispose();
  }
}

Common Metadata Patterns

Document Classification

with Document() as doc:
    doc.set_metadata("document_type", "invoice")
    doc.set_metadata("confidence", 0.95)
    doc.set_metadata("classification_model", "doc-classifier-v2")
    doc.set_metadata("classification_timestamp", "2024-01-15T10:30:00Z")

    # Alternative classifications
    doc.set_metadata("classifications", [
        {"type": "invoice", "confidence": 0.95},
        {"type": "receipt", "confidence": 0.03},
        {"type": "contract", "confidence": 0.02}
    ])
async function classifyDocument(doc: KddbDocument, predictions: Array<{type: string, confidence: number}>) {
  const topPrediction = predictions[0];

  await doc.setMetadataValue('documentType', topPrediction.type);
  await doc.setMetadataValue('confidence', topPrediction.confidence);
  await doc.setMetadataValue('classificationModel', 'doc-classifier-v2');
  await doc.setMetadataValue('classificationTimestamp', new Date().toISOString());
  await doc.setMetadataValue('classifications', predictions);
}

Processing Status

with Document() as doc:
    # Track processing status
    doc.set_metadata("status", "pending")
    doc.set_metadata("created_at", "2024-01-15T10:00:00Z")

    # After processing
    doc.set_metadata("status", "complete")
    doc.set_metadata("processed_at", "2024-01-15T10:30:00Z")
    doc.set_metadata("processing_time_ms", 1500)
    doc.set_metadata("processor_version", "1.2.3")
async function trackProcessingStatus(doc: KddbDocument) {
  // Initial status
  await doc.setMetadataValue('status', 'pending');
  await doc.setMetadataValue('createdAt', new Date().toISOString());

  // After processing
  const startTime = Date.now();
  // ... processing ...
  const endTime = Date.now();

  await doc.setMetadataValue('status', 'complete');
  await doc.setMetadataValue('processedAt', new Date().toISOString());
  await doc.setMetadataValue('processingTimeMs', endTime - startTime);
  await doc.setMetadataValue('processorVersion', '1.2.3');
}

Audit Trail

with Document() as doc:
    doc.set_metadata("created_by", "user@example.com")
    doc.set_metadata("created_at", "2024-01-15T10:00:00Z")
    doc.set_metadata("modified_by", "admin@example.com")
    doc.set_metadata("modified_at", "2024-01-15T14:30:00Z")
    doc.set_metadata("modification_history", [
        {
            "user": "user@example.com",
            "action": "created",
            "timestamp": "2024-01-15T10:00:00Z"
        },
        {
            "user": "admin@example.com",
            "action": "approved",
            "timestamp": "2024-01-15T14:30:00Z"
        }
    ])
async function addAuditEntry(doc: KddbDocument, user: string, action: string) {
  // Get existing history
  const history = (await doc.getMetadataValue('modificationHistory')) || [];

  // Add new entry
  history.push({
    user: user,
    action: action,
    timestamp: new Date().toISOString()
  });

  // Update metadata
  await doc.setMetadataValue('modifiedBy', user);
  await doc.setMetadataValue('modifiedAt', new Date().toISOString());
  await doc.setMetadataValue('modificationHistory', history);
}

Metadata vs Node Features

AspectMetadataNode Features
ScopeDocument-levelPer-node
PurposeDocument propertiesNode-specific data
ExamplesTitle, author, statusFont, position, OCR confidence
Accessdoc.metadata / doc.get_metadata()node.get_feature()
QueryingNot queryable via selectorsQueryable via selectors