Skip to main content

Multimodal & Media

Foil supports multimodal traces — mix text, documents, spreadsheets, code files, and images in your span inputs and outputs. Upload files via the SDK, and Foil automatically extracts text content for evaluations and analysis.
Check out the multimodal examples for complete, runnable code in both JavaScript and Python.

How It Works

  1. You upload a file via the SDK — it’s stored in S3 and categorized automatically
  2. The ingestion service extracts text content (for documents, spreadsheets, code)
  3. You reference the uploaded media in span inputs/outputs using content blocks
  4. Evaluations automatically include extracted text when analyzing spans

Supported Media Categories

Media category is auto-detected from the file’s MIME type. You can associate up to 20 files per span.

Content Blocks

Content blocks let you mix text and media references in span inputs and outputs:
  • Text blocks — plain text content ({ type: 'text', text: '...' })
  • Media blocks — references to uploaded media ({ type: 'media', mediaId: '...' })

Auto-Upload with ContentBlock.file() (JavaScript)

The JavaScript SDK supports ContentBlock.file() which automatically uploads files before the span is sent — no manual uploadMedia() call needed:
ContentBlock.file() accepts a file path, Buffer, or ReadStream:

Uploading Media

Upload files directly with uploadMedia() for more control over the upload lifecycle.

Upload Options

Using Media in Spans

After uploading, reference media in span inputs and outputs using content blocks.
Or use ContentBlock.file() to skip manual upload:

Retrieving Media

When evaluations run on spans containing media content blocks, Foil automatically includes extracted text (up to 15,000 characters per file) in the analysis. No manual configuration needed.

Limitations

Current limitations of multimodal support:
  • No vision model analysis for images — dimensions are extracted but image content is not analyzed by a vision model
  • No audio/video transcription — audio and video files are stored but not processed yet
  • No archive or notebook processing — ZIP files and Jupyter notebooks are stored as-is
  • 20 files per span maximum
  • Files over 100 MB require presigned upload (contact support)
  • Extracted text is capped at 100 KB per file; evaluation prompts use up to 15,000 characters per file

Best Practices

Upload files first and use the returned mediaId in your content blocks. This ensures media is available when the span is processed. Alternatively, use ContentBlock.file() (JavaScript) to handle this automatically.
Instead of embedding file contents as plain text, use content blocks. This enables Foil to track media associations, provide download links, and include extracted content in evaluations.
Text extraction is asynchronous. If you need extracted content immediately, poll getMedia() until processing.status is 'completed'.
When possible, pass file paths to uploadMedia() or ContentBlock.file(). This lets the SDK auto-detect the filename and MIME type. When using Buffer/bytes, always provide a filename.

Next Steps

Traces & Spans

Learn about traces and span hierarchy

Alerting

Get notified on quality issues