# Shoppable Widgets

> Shoppable widgets

- Skill: `gotolstoy/shoppable-widgets` (Agent Skill)
- Install (CLI): `npx skillmds@latest add gotolstoy/shoppable-widgets`
- Raw SKILL.md: https://api.skillmd.com/api/skills/gotolstoy/shoppable-widgets/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: GoTolstoy (https://skillmd.com/u/gotolstoy)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/gotolstoy/shoppable-widgets

---


# Shoppable widgets

Turn library videos into shoppable storefront experiences: tag products on videos, build onsite widgets (Stories, Carousel, Spotlight, For You Feed, Tile, Collection Grid, Bubble Feed), publish them, and read Meta ads performance. All via the Tolstoy Library MCP.

## Mental model

- A **video** becomes **shoppable** when you tag store **products** on it (`tag_video_product`). Tagged videos feed the `product_tagged` playlist and show on those products' pages.
- A **widget** (onsite project) is what shoppers see on the store — it draws from playlists/rules and renders as Stories, Carousel, Spotlight, etc.
- A widget is **live** in Tolstoy when `live: true`, but storefront visibility also needs the Tolstoy app embed enabled in the Shopify theme (one-time, per store). The publish result spells out the steps — relay them.
- Tools default to the **connected store**; pass `appUrl` (full or a distinctive fragment) to target another of the account's stores. Use `list_stores` to see them.

## Make a video shoppable

1. Find the video — `search_assets` (by name) or `list_assets` (recent/favorites).
2. Find the product — `search_products` with the product title → take its `externalProductId`.
3. Tag it — `tag_video_product { vodAssetId, addProductIds: [externalProductId], appUrl? }`. Untag with `removeProductIds`.
   - The result reports per-product success/failure — if a product id belongs to another store, it fails; pass the matching `appUrl`.

## Build & publish a widget

1. **Create** — `create_widget { type }` where type is `stories`, `carousel`, `spotlight`, `tv` (For You Feed), `tile-embed`, `collectionPageTile`, or `bubble-feed`. It starts **offline** with the platform's defaults (most start from product-tagged videos).
2. **Inspect** — `get_widget { publishId }` shows the actual media it will render, content rules, and PDP mode. For PDP-mode widgets, pass `productId` to see exactly what a given product page would show.
3. **Adjust** — `update_widget { publishId, ... }`: rename, toggle `isPdpMode`, set `maxMediaAgeDays`, or replace content (`sourcesIn`/`sourcesOut` playlists, `rules` for pin/hide/manual/sort). Read with `get_widget` first; these are full replacements.
4. **Publish** — `update_widget { publishId, live: true }`. Relay the returned app-embed setup steps; confirm whether the embed is already enabled on the store.

## Read ad performance

- `list_ad_campaigns` — Meta campaigns with real delivery status. Report `effectiveStatus`, not just `status`; ACTIVE-but-not-delivering is not "live."
- `get_ads_performance { level, datePreset }` — spend, ROAS, CTR, purchases. Use `level: "ad"` for winner/loser creative comparisons. If purchases are 0 but custom conversions exist, the account tracks conversions differently — don't call it unprofitable.
- `publish_to_meta_ads_library { asset }` — push a library video/image into Meta Ads Manager, ready for ad creation. No campaign or spend is created. With multiple ad accounts, pass `adAccountId`.

There is **no** create/activate/pause-campaign tool — money-moving operations stay in the Tolstoy platform on purpose.

## End-to-end example

> "Make my unboxing video shoppable for the DBTK 1 shirt, put it in a stories widget, publish it, and show me how my ads are doing."
> 1. `search_assets "unboxing"` → vodAssetId
> 2. `search_products "DBTK 1"` → externalProductId
> 3. `tag_video_product { vodAssetId, addProductIds: [externalProductId] }`
> 4. `create_widget { type: "stories" }` → publishId
> 5. `get_widget { publishId, productId: "<DBTK 1 id>" }` → confirm the video shows on that product's page
> 6. `update_widget { publishId, live: true }` → relay app-embed steps
> 7. `get_ads_performance { level: "campaign", datePreset: "last_7d" }`

## Notes

- Multi-store: a product id is store-specific. Keep `appUrl` consistent across `search_products` and `tag_video_product`.
- `get_widget` content is the unscoped pool unless you pass `productId`; PDP-mode widgets show only the per-product subset to shoppers.
- App-aware clients (ChatGPT, Claude) render a shoppable-widget card grid and media previews inline.

