Skip to main content
This guide shows you how to add video and image elements to your scenes. Media elements are overlays placed on top of a scene’s background, for example a product demo playing picture-in-picture in a corner, a screenshot next to your narration, or an AI-generated illustration. They live in the same scene-level elements array as shape and text elements, and can be freely mixed with them.

What You’ll Learn

Three Ways to Add Media

Bring your own URL, search the stock library, or generate with AI

Positioning and Sizing

Anchor presets, exact placement, and automatic fit-to-screen sizing

Playback Settings

Control looping and audio muting for video elements

Color Overlays

Tint an individual element, independent of the scene background

Before You Begin

Make sure you have:
Media elements are processed by the v3 storyboard engine. Any scene that includes an elements array is automatically routed to v3; you do not need to set storyboardVersion yourself.

How Media Elements Work

Set type to "video" or "image", then tell Pictory where the media comes from. Every media element uses exactly one of three sources:
Source fieldWhat it doesBest for
visualUrlUses the file at the URL you provideYour own footage, product shots, screenshots
searchFilterSearches the stock library with your queryQuick, relevant b-roll and imagery without hosting files
aiVisualGenerates the media from a text promptVisuals that do not exist yet: illustrations, concept shots
"scenes": [
  {
    "story": "Your scene narration here.",
    "elements": [
      // 1. Your own video, playing picture-in-picture
      {
        "type": "video",
        "visualUrl": "https://example.com/videos/product-demo.mp4",
        "position": "bottom-right",
        "width": "30%"
      },

      // 2. A stock image found by search
      {
        "type": "image",
        "searchFilter": { "query": "growth chart on laptop screen" },
        "top": "10%",
        "left": "6%"
      },

      // 3. An AI-generated illustration
      {
        "type": "image",
        "aiVisual": {
          "prompt": "minimalist illustration of a rocket launching from a laptop",
          "model": "seedream3.0"
        },
        "position": "center-right",
        "width": "25%"
      }
    ]
  }
]
  • A maximum of 20 elements per scene is allowed (shapes, text, and media combined).
  • Provide exactly one of visualUrl, searchFilter, or aiVisual per media element; sending two or more is rejected.

Source 1: Your Own Media (visualUrl)

Point visualUrl at any publicly reachable video or image file. Pictory reads the file’s duration and dimensions automatically, so the element keeps its natural proportions.
FieldTypeRequiredDescription
typestringYes"video" or "image"
visualUrlstringYesURL of the media file
{ "type": "video", "visualUrl": "https://example.com/videos/demo.mp4", "position": "bottom-right", "width": "30%" }

Source 2: Stock Library Search (searchFilter)

Describe what you want and Pictory finds a matching visual in the stock library. For media elements, searchFilter takes a single field:
FieldTypeRequiredDescription
typestringYes"video" or "image". This also decides whether stock videos or stock photos are searched
searchFilter.querystringYesWhat to search for, in plain language
{ "type": "image", "searchFilter": { "query": "team celebrating in office" }, "position": "top-left", "width": "25%" }
The search also respects the request-level language field, so non-English queries work naturally.
If the search finds no suitable match, the element is simply left out of the video. The rest of the scene still renders and the request does not fail. Prefer specific, visual queries (“growth chart on laptop screen”) over abstract ones (“success”).

Source 3: AI-Generated Media (aiVisual)

Generate the element from a text prompt. The aiVisual object accepts the same fields as background AI visuals:
FieldTypeRequiredDescription
aiVisual.promptstringNoWhat to generate. If omitted, the scene’s narration guides the generation
aiVisual.modelstringYesImage models: flux-schnell, seedream3.0, nanobanana, nanobanana-pro. Video models: pixverse5.5, veo3.1_fast, veo3.1
aiVisual.mediaStylestringNophotorealistic, artistic, cartoon, minimalist, vintage, futuristic
aiVisual.videoDurationstringNoVideo elements only, e.g. "8s". Allowed values depend on the model. Defaults to the model’s shortest duration
{
  "type": "video",
  "aiVisual": { "prompt": "abstract waves of light on a dark background", "model": "veo3.1", "videoDuration": "8s" },
  "top": "40%",
  "left": "55%"
}
AI generation consumes AI Credits according to the selected model’s rate. See the per-model credit tables in the AI Background Images and AI Background Videos guides, and Understanding AI Credits. If your account does not have enough credits, the element is skipped and the rest of the video still renders.

Positioning and Sizing

Media elements use the same positioning rules as shapes and text: a position anchor or explicit top/left offsets, never both.
FieldTypeDescription
positionstringAnchor region: top-left, top-center, top-right, center-left, center, center-right, bottom-left, bottom-center, bottom-right. Defaults to center
topstringVertical offset as a percentage from the top, e.g. "40%". Cannot be combined with position
leftstringHorizontal offset as a percentage from the left, e.g. "55%". Cannot be combined with position
widthstringElement width as a percentage of the canvas, e.g. "30%". Height follows automatically from the media’s own proportions

Sizing: exact or automatic

  • If you provide width, it is used exactly as given. A width of "100%" spans the full canvas.
  • If you omit width, the element is sized automatically: it starts at 30% of the canvas and shrinks as needed so the whole element stays on screen, taking into account its position and the media’s proportions. A portrait clip placed near the bottom of a landscape video, for example, is scaled down so it does not run off the bottom edge.

Recipe: full-screen video element

To cover the entire frame with a video element, combine explicit offsets at the origin with a 100% width:
{
  "type": "video",
  "visualUrl": "https://example.com/videos/loop.mp4",
  "top": "0%",
  "left": "0%",
  "width": "100%",
  "settings": { "loop": true, "mute": true }
}
The element covers the frame exactly when the media’s aspect ratio matches the video’s aspect ratio (for example, a 16:9 clip in a 16:9 video).

Playback Settings (Video Elements)

Video elements accept an optional settings object:
FieldTypeDefaultDescription
settings.loopbooleantrueRestart the clip when it ends, for as long as the scene lasts
settings.mutebooleantrueSilence the clip’s own audio so it does not compete with your narration
Both default to true, which is what you want for most picture-in-picture overlays. Set mute: false only when the element’s own audio should be heard.
{ "type": "video", "visualUrl": "https://example.com/testimonial.mp4", "settings": { "loop": false, "mute": false } }

Color Overlay on an Element

Any media element can carry its own colorOverlay, the same tint control available for scene backgrounds, applied to just this element:
{
  "type": "image",
  "searchFilter": { "query": "city skyline at dusk" },
  "position": "center-left",
  "width": "35%",
  "colorOverlay": { "color": "#1A1A2E", "opacity": 0.3 }
}

Complete Example

import axios from "axios";

const API_BASE_URL = "https://api.pictory.ai/pictoryapis";
const API_KEY = "YOUR_API_KEY";

async function createVideoWithMediaElements() {
  const response = await axios.post(
    `${API_BASE_URL}/v2/video/storyboard`,
    {
      videoName: "video_with_media_elements",
      scenes: [
        {
          story: "Here is the dashboard our customers use every day.",
          elements: [
            // Your own screen recording, picture-in-picture
            {
              type: "video",
              visualUrl: "https://example.com/videos/dashboard-demo.mp4",
              position: "bottom-right",
              width: "35%",
              settings: { loop: true, mute: true },
            },
          ],
        },
        {
          story: "Teams that switch to our platform report faster delivery within weeks.",
          elements: [
            // A stock image found by search, tinted to match the brand
            {
              type: "image",
              searchFilter: { query: "team collaborating around a laptop" },
              top: "12%",
              left: "8%",
              width: "30%",
              colorOverlay: { color: "#1A1A2E", opacity: 0.25 },
            },
            // An AI-generated illustration
            {
              type: "image",
              aiVisual: {
                prompt: "minimalist illustration of a rising bar chart with a rocket",
                model: "seedream3.0",
                mediaStyle: "minimalist",
              },
              position: "center-right",
              width: "25%",
            },
          ],
        },
      ],
    },
    {
      headers: {
        "Content-Type": "application/json",
        Authorization: API_KEY,
      },
    }
  );

  console.log("✓ Storyboard creation started!");
  console.log("Job ID:", response.data.data.jobId);
}

createVideoWithMediaElements();
import requests

API_BASE_URL = "https://api.pictory.ai/pictoryapis"
API_KEY = "YOUR_API_KEY"

def create_video_with_media_elements():
    response = requests.post(
        f"{API_BASE_URL}/v2/video/storyboard",
        headers={"Content-Type": "application/json", "Authorization": API_KEY},
        json={
            "videoName": "video_with_media_elements",
            "scenes": [
                {
                    "story": "Here is the dashboard our customers use every day.",
                    "elements": [
                        {
                            "type": "video",
                            "visualUrl": "https://example.com/videos/dashboard-demo.mp4",
                            "position": "bottom-right",
                            "width": "35%",
                            "settings": {"loop": True, "mute": True},
                        },
                    ],
                },
                {
                    "story": "Teams that switch to our platform report faster delivery within weeks.",
                    "elements": [
                        {
                            "type": "image",
                            "searchFilter": {"query": "team collaborating around a laptop"},
                            "top": "12%",
                            "left": "8%",
                            "width": "30%",
                            "colorOverlay": {"color": "#1A1A2E", "opacity": 0.25},
                        },
                        {
                            "type": "image",
                            "aiVisual": {
                                "prompt": "minimalist illustration of a rising bar chart with a rocket",
                                "model": "seedream3.0",
                                "mediaStyle": "minimalist",
                            },
                            "position": "center-right",
                            "width": "25%",
                        },
                    ],
                },
            ],
        },
    )

    print("✓ Storyboard creation started!")
    print("Job ID:", response.json()["data"]["jobId"])

create_video_with_media_elements()

When an Element Cannot Be Resolved

Media elements are designed to degrade gracefully. The element is left out of the video, without failing the request, when:
  • a searchFilter query finds no suitable stock match,
  • an aiVisual generation fails, or
  • the account does not have enough AI Credits for the generation.
Everything else in the scene (background, narration, other elements) still renders. If an expected element is missing from the preview, refine the search query, check your AI Credits balance, or verify the visualUrl is publicly reachable.

Next Steps

Shapes and Text Elements

Add badges, arrows, and decorative text alongside your media

Background Color Overlay

Tint the whole scene background for readability and branding

AI-Generated Visuals

Use the same AI models for full scene backgrounds

Get Project by ID

See how elements appear in the saved project structure