Media & File Uploads
Attach images, PDFs, and other binary files to traces and observations in TypeScript and Python.
Media & File Uploads
The SDK lets you attach binary content — images, PDFs, audio, and other files — to traces and observations. Media is uploaded asynchronously when the trace is flushed and referenced via a unique media ID.
Creating a Media Object
import { Media } from '@browserstack/ai-sdk';Media accepts four construction patterns:
From a file path:
import { Media } from '@browserstack/ai-sdk';
const media = new Media({
filePath: './screenshot.png',
contentType: 'image/png',
});From a Buffer or Uint8Array:
import * as fs from 'fs';
const imageBuffer = fs.readFileSync('./chart.png');
const media = new Media({
contentBytes: imageBuffer,
contentType: 'image/png',
});From a Base64 data URI:
const media = new Media({
base64DataUri: 'data:image/jpeg;base64,/9j/4AAQSkZJRgAB...',
});From an unsigned URL:
const media = new Media({
unsignedUrl: 'https://your-storage.example.com/screenshot.png',
});Constructor options:
new Media(options?: {
contentType?: MediaContentType; // MIME type (e.g. 'image/png')
data?: Buffer | Uint8Array; // raw bytes
contentBytes?: Buffer | Uint8Array; // alias for data
base64DataUri?: string; // data URI string
filePath?: string; // local file path (sync read)
unsignedUrl?: string; // reference a hosted URL
})from browserstack_ai_sdk import MediaFrom a file path:
image = Media(
file_path="/path/to/screenshot.png",
content_type="image/png",
)From bytes:
with open("/path/to/image.jpg", "rb") as f:
image_bytes = f.read()
image = Media(
content_bytes=image_bytes,
content_type="image/jpeg",
)From a Base64 data URI:
image = Media(
base64_data_uri="data:image/png;base64,iVBORw0KGgo...",
)Constructor parameters:
| Parameter | Type | Description |
|---|---|---|
file_path | str | Path to a local file |
content_bytes | bytes | Raw binary content |
base64_data_uri | str | Base64-encoded data URI (includes content type) |
content_type | str | MIME type (e.g., "image/png", "image/jpeg") |
Provide exactly one of file_path, content_bytes, or base64_data_uri.
Media and file upload support for the Java SDK is coming soon. Track progress in our SDK changelog.
Supported Media Types
| Type | Examples |
|---|---|
| Images | image/png, image/jpeg, image/gif, image/webp |
| Documents | application/pdf |
| Audio | audio/mpeg, audio/wav |
| Video | video/mp4 |
| Text | text/plain, text/html |
| Binary | application/octet-stream |
Attaching Media to Traces
Pass Media objects anywhere an input, output, or metadata field is accepted. The SDK serializes them to reference tokens and uploads the binary content when flushing.
In a generation input:
import { AISDK, Media } from '@browserstack/ai-sdk';
import OpenAI from 'openai';
import { readFileSync } from 'node:fs';
const testOps = new AISDK({
publicKey: process.env.AISDK_PUBLIC_KEY,
secretKey: process.env.AISDK_SECRET_KEY,
});
const openai = new OpenAI();
const screenshot = new Media({
filePath: './page.png',
contentType: 'image/png',
});
const imageDataUrl = `data:image/png;base64,${readFileSync('./page.png').toString('base64')}`;
const trace = testOps.trace({ name: 'vision-analysis' });
const generation = trace.generation({
name: 'describe-image',
model: 'gpt-4o',
input: [
{
role: 'user',
content: [
{ type: 'text', text: 'Describe what you see in this screenshot.' },
{
type: 'image_url',
image_url: { url: imageDataUrl },
},
],
},
],
metadata: { screenshot }, // attach media to metadata for storage
});
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [
{
role: 'user',
content: [
{ type: 'text', text: 'Describe what you see in this screenshot.' },
{ type: 'image_url', image_url: { url: imageDataUrl } },
],
},
],
});
generation.end({ output: response.choices[0].message.content });
trace.update({ output: response.choices[0].message.content });
await testOps.shutdown();In trace metadata:
const report = new Media({
filePath: './evaluation-report.pdf',
contentType: 'application/pdf',
});
const trace = testOps.trace({
name: 'document-processing',
input: { filename: 'evaluation-report.pdf' },
metadata: { sourceDocument: report },
});Pass Media objects in the input or output fields of a generation:
import os
from browserstack_ai_sdk import AISDK, Media
client = AISDK(
public_key=os.environ["AISDK_PUBLIC_KEY"],
secret_key=os.environ["AISDK_SECRET_KEY"],
)
screenshot = Media(
file_path="/tmp/ui_screenshot.png",
content_type="image/png",
)
trace = client.trace(name="ui-analysis", session_id="session-abc")
generation = trace.start_generation(
name="analyze-screenshot",
model="gpt-4o",
input=[
{
"role": "user",
"content": [
{"type": "text", "text": "Describe any UI issues in this screenshot."},
screenshot,
],
}
],
)
import openai
openai_client = openai.OpenAI(api_key=os.environ["OPENAI_API_KEY"])
response = openai_client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "Describe any UI issues in this screenshot."},
{
"type": "image_url",
"image_url": {"url": f"data:image/png;base64,<base64>"},
},
],
}
],
)
generation.update(output=response.choices[0].message.content)
generation.end()
trace.update(output=response.choices[0].message.content)
client.flush()Using @observe with media:
import os
from browserstack_ai_sdk import observe, AISDK, Media
import openai
client = AISDK(
public_key=os.environ["AISDK_PUBLIC_KEY"],
secret_key=os.environ["AISDK_SECRET_KEY"],
)
openai_client = openai.OpenAI(api_key=os.environ["OPENAI_API_KEY"])
@observe(name="analyze-image")
def analyze_image(image_path: str) -> str:
image = Media(file_path=image_path, content_type="image/png")
with open(image_path, "rb") as f:
import base64
b64 = base64.b64encode(f.read()).decode()
response = openai_client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "What do you see in this image?"},
{"type": "image_url", "image_url": {"url": f"data:image/png;base64,{b64}"}},
],
}
],
)
return response.choices[0].message.content
result = analyze_image("/tmp/photo.png")
print(result)Media and file upload support for the Java SDK is coming soon. Track progress in our SDK changelog.
Reference String Format
Uploaded media is referenced in traces with the format:
@@@AIOPS_INTERNALMedia:type=image/png|id=<media-id>|source=<source>@@@Parse reference strings back to their components:
const ref = '@@@AIOPS_INTERNALMedia:type=image/png|id=abc123|source=s3@@@';
const parsed = Media.parseReferenceString(ref);
// { mediaId: 'abc123', source: 's3', contentType: 'image/png' }from browserstack_ai_sdk import Media
parsed = Media.parse_reference_string(
"@@@AIOPS_INTERNALMedia:type=image/png|id=abc123|source=upload@@@"
)
print(parsed["media_id"]) # "abc123"
print(parsed["content_type"]) # "image/png"Media and file upload support for the Java SDK is coming soon.