Skip to content
Tutti gli articoli
Blog·5 marzo 2026

Come funziona la Render API di Screenshots Live — Guida pratica per automatizzare i listing degli store

Un walkthrough tecnico su come la Render API di Screenshots Live elabora i template, applica gli override YAML e genera screenshot pronti per lo store — con esempi di codice reali e pattern CI/CD per setup whitelabel.

Cosa copre questo post

Se distribuisci app whitelabel — o anche solo un'app con più listing negli store — probabilmente ti sei già scontrato con il problema degli screenshot. Apple vuole screenshot per ogni dimensione di dispositivo. Google Play vuole il suo set. Supporta tre lingue e hai triplicato il lavoro. Adesso moltiplica tutto per il numero di varianti di brand che mantieni.

Il post precedente ha spiegato perché esiste Screenshots Live. Questo è il seguito pratico: come è progettata la render API, cosa si aspetta e come integrarla nella tua build pipeline perché gli screenshot smettano di essere un lavoro manuale.

Come è progettata la pipeline di rendering

Il sistema di rendering non è un endpoint sincrono "mandi la request, ricevi l'immagine". È una pipeline basata su job, il che conta quando fai rendering batch di decine o centinaia di screenshot.

Il flusso:

  1. Invii una richiesta di rendering con un ID template e override YAML opzionali (testo, screenshot, device frame — qualsiasi cosa marcata come intercambiabile).
  2. Validazione — il sistema verifica che il tuo template esista, che sia tuo e che ogni campo che vuoi sovrascrivere sia effettivamente permesso. Gli URL vengono validati contro range IP privati e protocolli ristretti.
  3. Coda — il job entra in una coda BullMQ basata su Redis. La tua chiamata API ritorna immediatamente con un jobId e stato Pending. Questo è il punto chiave: non aspetti che il rendering finisca.
  4. Rendering — un worker basato su Rust prende il job, carica template e immagini (con cache LRU per render ripetuti), carica i font, renderizza il canvas usando Skia e genera l'output.
  5. Pacchettizzazione — le immagini renderizzate vengono zippate e caricate nell'object storage.
  6. Download — fai polling sull'endpoint di stato. Quando è Completed, chiami l'endpoint di download per un URL prefirmato (valido per 1 ora).

Il design asincrono è intenzionale. Quando devi renderizzare 50 template per un release, li spari tutti e raccogli i risultati. Nessun blocco, nessun timeout.

Autenticazione

Serve un account Pro tier per accedere alla render API. Crea un API key dalla tua dashboard — apparirà come sa_live_.... Ogni richiesta lo usa come Bearer token:

Authorization: Bearer sa_live_your_key_here

Template: Come sono strutturati

Tutto ruota attorno ai template. Un template è un canvas che costruisci nell'editor visuale — piazzi blocchi di testo, device frame, immagini e sfondi. Ogni elemento sul canvas è un item con un UUID unico.

Per l'automazione, il concetto critico sono i campi intercambiabili (swappable field). Non ogni proprietà di ogni item è sovrascrivibile via API. Un admin configura quali campi sono intercambiabili — contenuto testuale, famiglia di font, dimensione font, colori, URL screenshot, ID device frame, ecc. È una restrizione deliberata: impedisce ai consumatori dell'API di rompere accidentalmente il layout cambiando posizioni o dimensioni che il designer ha fissato.

Pensalo come un contratto tra il tuo designer e la tua pipeline: il designer è proprietario del layout, la pipeline è proprietaria del contenuto.

Il sistema di override YAML

Qui diventa interessante per l'automazione. Invece di renderizzare un template esattamente come è stato salvato, invii YAML che sovrascrive campi specifici di item specifici.

Step 1: Ottenere lo scaffold YAML

Ogni template ha un endpoint scaffold che restituisce tutti i campi intercambiabili come YAML commentato:

curl -H "Authorization: Bearer sa_live_your_key_here" \
  https://api.screenshots.live/templates/IL_TUO_TEMPLATE_ID/yaml

Riceverai qualcosa tipo:

templateId: "550e8400-e29b-41d4-a716-446655440000"
items:
  - itemId: "7c9e6679-7425-40de-944b-e07fc1f90ae7"
    type: Text
    # text: "Il tuo titolo qui"
    # fontFamily: "Inter"
    # fontSize: 48
    # color: "#FFFFFF"
  - itemId: "a1b2c3d4-5678-90ab-cdef-1234567890ab"
    type: DeviceFrame
    # screenshotUrl: "https://..."
    # frameId: "..."

Decommenta quello che vuoi sovrascrivere. Lascia il resto — quei campi mantengono i valori predefiniti del template.

Step 2: Inviare il render

curl -X POST https://api.screenshots.live/render/api \
  -H "Authorization: Bearer sa_live_your_key_here" \
  -H "Content-Type: text/yaml" \
  -d '
templateId: "550e8400-e29b-41d4-a716-446655440000"
items:
  - itemId: "7c9e6679-7425-40de-944b-e07fc1f90ae7"
    type: Text
    text: "Traccia le tue consegne"
    color: "#1A73E8"
  - itemId: "a1b2c3d4-5678-90ab-cdef-1234567890ab"
    type: DeviceFrame
    screenshotUrl: "https://your-cdn.com/screenshots/home-screen.png"
'

Step 3: Controllare lo stato

curl -H "Authorization: Bearer sa_live_your_key_here" \
  https://api.screenshots.live/render/api/JOB_ID

Lo stato progredisce: PendingActiveCompleted (o Failed). La maggior parte dei template viene renderizzata in pochi secondi.

Step 4: Scaricare

curl -H "Authorization: Bearer sa_live_your_key_here" \
  https://api.screenshots.live/render/JOB_ID/download

Restituisce un URL prefirmato. Il download è un ZIP con le immagini renderizzate.

Caricare screenshot direttamente

Non serve hostare gli screenshot da qualche parte solo per passare un URL. L'endpoint /render/api/with-pictures accetta upload multipart:

curl -X POST https://api.screenshots.live/render/api/with-pictures \
  -H "Authorization: Bearer sa_live_your_key_here" \
  -F 'yaml=templateId: "IL_TUO_TEMPLATE_ID"
items:
  - itemId: "DEVICE_FRAME_ITEM_ID"
    type: DeviceFrame
    screenshotUrl: "picture://home-screen.png"' \
  -F 'pictures=@./screenshots/home-screen.png'

Il protocollo picture:// referenzia i file caricati per nome. Puoi allegare fino a 200 file da 10MB ciascuno. Questo è ciò che rende l'API pratica per CI/CD — la tua pipeline cattura screenshot e li mandi direttamente al rendering senza storage intermedio.

Esempio reale: Pipeline whitelabel

Uno scenario concreto: gestisci 5 brand whitelabel, ognuno necessita di screenshot App Store in 3 lingue per 5 schermate chiave. Sono 75 immagini renderizzate per release.

Il tuo designer ha creato un template per schermata nell'editor, con testo headline e device frame marcati come intercambiabili. La tua pipeline CI (GitLab, GitHub Actions, qualsiasi cosa) cattura screenshot raw per brand e lingua con snapshot/screengrab di Fastlane.

Lo script che unisce tutto:

#!/bin/bash

API_KEY="sa_live_your_key_here"
API_BASE="https://api.screenshots.live"

BRANDS=("acme" "globex" "initech" "umbrella" "stark")
LOCALES=("en" "de" "es")
SCREENS=("home" "profile" "search" "settings" "checkout")

declare -A TEMPLATES
TEMPLATES[home]="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
TEMPLATES[profile]="aaaaaaaa-bbbb-cccc-dddd-ffffffffffff"

declare -A HEADLINES
HEADLINES[home:en]="Track your deliveries"
HEADLINES[home:de]="Verfolge deine Lieferungen"
HEADLINES[home:es]="Rastrea tus entregas"

JOB_IDS=()

for brand in "${BRANDS[@]}"; do
  for locale in "${LOCALES[@]}"; do
    for screen in "${SCREENS[@]}"; do
      HEADLINE="${HEADLINES[$screen:$locale]}"
      BRAND_COLOR=$(cat "brands/$brand/primary-color.txt")

      RESPONSE=$(curl -s -X POST "$API_BASE/render/api/with-pictures" \
        -H "Authorization: Bearer $API_KEY" \
        -F "yaml=templateId: \"${TEMPLATES[$screen]}\"
items:
  - itemId: \"TEXT_ITEM_UUID\"
    type: Text
    text: \"$HEADLINE\"
    color: \"$BRAND_COLOR\"
  - itemId: \"FRAME_ITEM_UUID\"
    type: DeviceFrame
    screenshotUrl: \"picture://${screen}.png\"" \
        -F "pictures=@./artifacts/$brand/$locale/${screen}.png")

      JOB_ID=$(echo "$RESPONSE" | jq -r '.data.jobId')
      JOB_IDS+=("$JOB_ID|$brand|$locale|$screen")
    done
  done
done

echo "${#JOB_IDS[@]} job inviati. In attesa dei risultati..."

for entry in "${JOB_IDS[@]}"; do
  IFS='|' read -r job_id brand locale screen <<< "$entry"
  while true; do
    STATUS=$(curl -s -H "Authorization: Bearer $API_KEY" \
      "$API_BASE/render/api/$job_id" | jq -r '.status')
    if [ "$STATUS" = "Completed" ]; then
      URL=$(curl -s -H "Authorization: Bearer $API_KEY" \
        "$API_BASE/render/$job_id/download" | jq -r '.downloadUrl')
      mkdir -p "./output/$brand/$locale"
      curl -s -o "./output/$brand/$locale/${screen}.zip" "$URL"
      echo "Fatto: $brand/$locale/$screen"
      break
    elif [ "$STATUS" = "Failed" ]; then
      echo "ERRORE: $brand/$locale/$screen"
      break
    fi
    sleep 2
  done
done

75 render job, tutti sparati in parallelo, poi polled e scaricati. In una pipeline reale aggiungeresti retry logic e polling parallelo, ma il pattern è chiaro. Inseriscilo nel tuo .gitlab-ci.yml o GitHub Actions e l'intero flusso — dal push del codice agli screenshot pronti per lo store — gira senza intervento umano.

Scambiare device frame

I device frame sono gli overlay mockup — iPhone 16 Pro, Pixel 9, iPad Air, Galaxy S24. Sono precaricati nel tuo account e referenziati per UUID. Lo stesso template può essere renderizzato con frame diversi:

items:
  - itemId: "FRAME_ITEM_UUID"
    type: DeviceFrame
    screenshotUrl: "picture://home.png"
    frameId: "IPHONE_16_PRO_FRAME_UUID"

Così risolvi la divisione App Store vs Google Play: stesso layout template, stesso screenshot, frame diverso. Due render job — uno con il frame iPhone, uno con il Pixel — e hai coperto entrambi gli store con un solo template.

Rate limit e quote

Numeri per pianificare:

  • Render API: 5 richieste ogni 60 secondi
  • Polling stato: 60 richieste ogni 60 secondi
  • Render giornalieri: 100 al giorno su Pro tier
  • Upload immagini: max 200 file per richiesta, 10MB ciascuno

Per setup whitelabel grandi, il rate limit sulle submission di render è il collo di bottiglia. Aggiungi piccole pause tra i batch. Il design async aiuta — le submission sono veloci, il rendering effettivo avviene in background.

Validazione YAML

Il parser YAML è deliberatamente rigoroso: niente ancore, niente alias, niente tag custom, max 1MB. Se qualcosa non va, il messaggio di errore ti dice esattamente cosa — nome campo sbagliato, campo non intercambiabile, formato UUID non valido, URL che punta a un range IP privato. Progettato per fallire velocemente e chiaramente — conta quando stai debuggando una pipeline CI alle 23.

E lo spec OpenAPI?

Se preferisci generare un client tipizzato invece di scrivere comandi curl, lo spec OpenAPI completo è disponibile su:

https://api.screenshots.live/render/openapi.json

E c'è una Swagger UI interattiva su:

https://api.screenshots.live/render/docs

Entrambi richiedono autenticazione Pro tier. Lo spec copre tutti gli endpoint render, i DTO e le risposte di errore — passalo a openapi-generator o orval e avrai un client tipizzato in TypeScript, Python, Go o quello che usi.

Conclusione

La render API è costruita per un workflow specifico: il tuo designer crea template nell'editor visuale, e il tuo codice li riempie con il contenuto giusto al momento del build. Per setup whitelabel dove lo stesso template deve funzionare per decine di brand e lingue, il sistema di override YAML significa che mantieni un template per layout di schermata invece di uno per combinazione brand-lingua-dispositivo.

Se hai gli screenshot raw coperti (Fastlane, Maestro, catture manuali — non importa) e devi automatizzare lo step di elaborazione, a questo serve Screenshots Live. La pipeline cattura screenshot, l'API li renderizza in immagini pronte per lo store, e Fastlane li carica. Nessun designer nel loop per release di routine.