---
title: "How to add a recent purchase popup with Claude (tested prompt and script)"
description: "A white card with a thumbnail of the bottle slides in from the left above the bottom edge, saying \"Jessica in Austin, TX just bought Glow Serum\" with a green check and \"2 minutes ago\", then slides back out. Install one skill and ask Claude Code, or run the Python script we tested yourself."
url: https://www.recharm.com/effects/recent-purchase-popup
---

# How to add a recent purchase popup with Claude

A white card with a thumbnail of the bottle slides in from the left above the bottom edge, saying "Jessica in Austin, TX just bought Glow Serum" with a green check and "2 minutes ago", then slides back out.

Made by the script on this page, from our own test clip.

## Get this effect

1. ### Switch to Code in your [Claude Desktop App](https://claude.com/download)

2. ### Install the skill (once)

   ```
   Install the Recharm video effects skill: download https://recharm-growth-staging.s3.us-east-2.amazonaws.com/website/downloads/recharm-video-effects.zip and unzip it into ~/.claude/skills
   ```

3. ### Ask for the effect

   ```
   Add a recent purchase popup to input.mp4
   Buyer: Jessica in Austin, TX
   Bought: just bought Glow Serum
   Ago: 2 minutes ago
   ```

## Several videos, several effects, one ask

Put your clips in the folder, mention them with @, and ask for everything at once. Claude runs one tested script after another on each clip, then joins them.

Add a recent purchase popup to **@clip1.mp4**, put a sale badge on **@clip2.mp4**, give **@clip3.mp4** a VHS look, then join all three with crossfades.

## Settings you can change

Ask Claude to change any of these, or edit them at the top of the script.

| Setting       | Default                  | What it does                                   |
| ------------- | ------------------------ | ---------------------------------------------- |
| `BUYER`       | `Jessica in Austin, TX`  | Bold top line. Use a real order.               |
| `BOUGHT`      | `just bought Glow Serum` | Middle line.                                   |
| `AGO`         | `2 minutes ago`          | Grey time-ago line beside the check mark.      |
| `START`       | `0.8`                    | Second the card starts sliding in.             |
| `HOLD`        | `3.0`                    | Seconds it stays in before sliding back out.   |
| `LEFT, TOP`   | `0.04, 0.78`             | Card's top-left corner as shares of the frame. |
| `CHECK_COLOR` | `(22, 163, 74)`          | Check mark color.                              |

## Without the skill

Don’t want to install the skill? Paste this prompt into Claude Code and Claude writes the script itself.

```
Add a recent purchase popup to input.mp4: a pure white (255, 255, 255) rounded card 80% of the frame width and 13.5% of the frame height, with a soft dark shadow, its top-left corner 4% across and 78% down. On its left, a rounded square thumbnail 22% of the card width: the middle of the video's first frame (a centered square 80% of the frame width), scaled down. To its right, "Jessica in Austin, TX" in black bold, "just bought Glow Serum" in dark grey under it, and a small green (22, 163, 74) circle with a white check mark followed by "2 minutes ago" in light grey at the bottom. The card slides in from off the left edge at 0.8 seconds over 0.35 seconds, easing out, stays in place for 3 seconds, then slides back out to the left over 0.35 seconds (gone by 4.5 seconds). Use Python with Pillow to draw it and ffmpeg to put it on the video (don't rely on ffmpeg's drawtext filter), keep the audio, and save it as output.mp4.
```

## Run it without Claude

This is the exact script we tested. Save it as `recent-purchase-popup.py` and run:

```
python3 recent-purchase-popup.py input.mp4 output.mp4
```

```
#!/usr/bin/env python3
"""Recent purchase popup: a small white card with a product thumbnail slides in at the bottom left saying who just bought.

Usage: python3 recent-purchase-popup.py input.mp4 output.mp4
Needs ffmpeg and Pillow (pip install pillow).
"""
import json
import math
import subprocess
import sys
from pathlib import Path

from PIL import Image, ImageDraw, ImageFilter, ImageFont

BUYER = "Jessica in Austin, TX"   # bold top line: put a real order here, never a made-up one
BOUGHT = "just bought Glow Serum"  # middle line
AGO = "2 minutes ago"              # grey time-ago line beside the check mark
START = 0.8              # second the card starts sliding in
SLIDE = 0.35             # seconds the slide in (and out) takes
HOLD = 3.0               # seconds it stays fully in before sliding back out
WIDTH = 0.80             # card width as a share of the frame width
LEFT, TOP = 0.04, 0.78   # card's top-left corner (0-1 across and down the frame)
CHECK_COLOR = (22, 163, 74)  # green check mark beside the time
FONTS = ["/System/Library/Fonts/Supplemental/Arial Bold.ttf",     # macOS
         "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",  # Linux
         "C:/Windows/Fonts/arialbd.ttf"]                          # Windows
REGULAR_FONTS = ["/System/Library/Fonts/Supplemental/Arial.ttf",     # macOS
                 "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",  # Linux
                 "C:/Windows/Fonts/arial.ttf"]                       # Windows
FONT_FILE = next((f for f in FONTS if Path(f).exists()), None) or sys.exit("No bold font found: add one to FONTS")
REGULAR_FILE = next((f for f in REGULAR_FONTS if Path(f).exists()), None) or sys.exit("No font found: add one to REGULAR_FONTS")

def thumbnail(size):
    """A square product shot cut from the middle of the video's first frame."""
    raw = subprocess.check_output(["ffmpeg", "-v", "error", "-i", src, "-frames:v", "1",
                                   "-f", "rawvideo", "-pix_fmt", "rgb24", "-"])
    still = Image.frombytes("RGB", (w, h), raw)
    side = min(w, h) * 0.8
    box = ((w - side) / 2, (h - side) / 2, (w + side) / 2, (h + side) / 2)
    return still.resize((size, size), Image.LANCZOS, box=box)

def card():
    """The white card with its soft shadow, drawn once."""
    cw = round(w * WIDTH)
    pad = round(cw * 0.04)
    thumb = round(cw * 0.22)
    ch = thumb + 2 * pad
    shadow = round(cw * 0.04)
    img = Image.new("RGBA", (cw + 2 * shadow, ch + 2 * shadow))
    draw = ImageDraw.Draw(img)
    draw.rounded_rectangle([shadow, shadow + 5, shadow + cw, shadow + ch + 5], radius=ch // 5, fill=(0, 0, 0, 90))
    img = img.filter(ImageFilter.GaussianBlur(shadow / 2))
    draw = ImageDraw.Draw(img)
    x0, y0 = shadow, shadow
    draw.rounded_rectangle([x0, y0, x0 + cw, y0 + ch], radius=ch // 5, fill="white")

    mask = Image.new("L", (thumb, thumb))
    ImageDraw.Draw(mask).rounded_rectangle([0, 0, thumb - 1, thumb - 1], radius=thumb // 6, fill=255)
    img.paste(thumbnail(thumb), (x0 + pad, y0 + pad), mask)

    tx = x0 + 2 * pad + thumb
    bold = ImageFont.truetype(FONT_FILE, round(cw * 0.050))
    regular = ImageFont.truetype(REGULAR_FILE, round(cw * 0.048))
    small = ImageFont.truetype(REGULAR_FILE, round(cw * 0.040))
    draw.text((tx, y0 + pad + round(thumb * 0.04)), BUYER, font=bold, fill=(20, 20, 20))
    draw.text((tx, y0 + pad + round(thumb * 0.38)), BOUGHT, font=regular, fill=(60, 60, 65))
    r = round(cw * 0.022)
    cy = y0 + pad + round(thumb * 0.84)
    draw.ellipse([tx, cy - r, tx + 2 * r, cy + r], fill=CHECK_COLOR)
    draw.line([(tx + r * 0.5, cy), (tx + r * 0.9, cy + r * 0.4), (tx + r * 1.5, cy - r * 0.4)], fill="white", width=max(2, r // 3))
    draw.text((tx + 2 * r + pad // 2, cy), AGO, font=small, fill=(120, 120, 125), anchor="lm")
    return img, shadow

def shown(t):
    """How far the card has slid in: 0 = hidden off the left edge, 1 = in place."""
    if t < START:
        return 0
    if t < START + SLIDE + HOLD:
        return ease_out(min((t - START) / SLIDE, 1))
    return 1 - ease_in(min((t - START - SLIDE - HOLD) / SLIDE, 1))

def ease_out(p):
    return 1 - (1 - p) ** 3

def ease_in(p):
    return p ** 3

def overlay(t):
    img = Image.new("RGBA", (w, h))
    k = shown(t)
    if k > 0:
        rest = round(w * LEFT) - margin
        hidden = -popup.width
        img.alpha_composite(popup, (round(hidden + (rest - hidden) * k), round(h * TOP) - margin))
    return img

def probe(path):
    info = json.loads(subprocess.check_output(["ffprobe", "-v", "error", "-select_streams", "v:0", "-show_entries",
                                               "stream=width,height,r_frame_rate:format=duration", "-of", "json", path]))
    s = info["streams"][0]
    num, den = s["r_frame_rate"].split("/")
    return s["width"], s["height"], s["r_frame_rate"], float(num) / float(den), float(info["format"]["duration"])

def render(src, out):
    """Draw overlay(t) on every frame of src and save to out, keeping the audio."""
    ff = subprocess.Popen(["ffmpeg", "-y", "-v", "error", "-i", src,
                           "-f", "rawvideo", "-pix_fmt", "rgba", "-s", f"{w}x{h}", "-r", rate, "-i", "-",
                           "-filter_complex", "[0:v][1:v]overlay=shortest=1,format=yuv420p[v]",
                           "-map", "[v]", "-map", "0:a?", "-c:v", "libx264", "-crf", "18", "-c:a", "copy", out],
                          stdin=subprocess.PIPE)
    for i in range(math.ceil(duration * fps)):
        ff.stdin.write(overlay(i / fps).tobytes())
    ff.stdin.close()
    if ff.wait():
        sys.exit("ffmpeg failed")

src, out = sys.argv[1:3]
w, h, rate, fps, duration = probe(src)
popup, margin = card()
render(src, out)
```

## More ugc and social proof

- [Comment reply overlay **Comment reply overlay**](https://www.recharm.com/effects/comment-reply-overlay)
- [Day counter **Day counter**](https://www.recharm.com/effects/day-counter)
- [Emoji rain **Emoji rain**](https://www.recharm.com/effects/emoji-rain)
- [Floating hearts **Floating hearts**](https://www.recharm.com/effects/floating-hearts)
- [Follow button animation **Follow button animation**](https://www.recharm.com/effects/follow-button-animation)

## Find 3x _winning ads_

Recharm cuts your ad footage into tagged, searchable clips: hooks, testimonials, product shots. Find the shots that win, add the effect with Claude, and ship 3x more ad edits.

[Start 14-day free trial](https://www.recharm.com/get-started)
