Zum Hauptinhalt springen

Embeddare il widget

Diese Seite ist in Ihrer Sprache noch nicht verfügbar. Es wird die Standardversion angezeigt.

Zuletzt aktualisiert: 27. Oktober 2026

Widget di prenotazione embeddabile

Il widget di prenotazione è un iframe da incollare in qualsiasi sito esterno. Renderizza un calendario localizzato degli eventi pubblicati imminenti dell'azienda e gestisce l'intero flusso di prenotazione — inclusa waitlist e handoff widget-auth.

Tre modi di integrazione

Apri Impostazioni azienda → tab Widget prenotazioni (/companies/{company}/edit?tab=widget — owner/admin). Scegli il percorso adatto alla piattaforma:

  • Condividi un link — il link diretto di prenotazione (/book/{company}) funziona ovunque: pulsanti di navigazione, bio, email. I link per canale pre-taggano sorgente/medium UTM. Zero codice.
  • Script di una riga (predefinito) — un solo tag <script src="…/api/embed/snippet.js?public_key=bw_pk_…">. Inserisce il pulsante di prenotazione dove lo incolli e carica il runtime da solo. Il clic apre il calendario come overlay. Richiede una pagina che esegua JavaScript — la maggior parte delle piattaforme lo fa.
  • Frame incorporato — un tag <iframe src="…/w/bw_pk_…">. /w/{public_key} crea la sessione embed lato server e reindirizza a /embed?token=…, quindi non serve alcun JS nella pagina ospite — il formato che sopravvive ai CMS che rimuovono gli script (blocchi embed di Wix e Squarespace, piani gratuiti wordpress.com). Compromesso: il calendario appare incorporato nella pagina invece che come overlay. Con Domini consentiti configurati, l'URL /w/ funziona solo dentro pagine di quei domini — aperto come link diretto (email, chat, host con referrerpolicy="no-referrer") risponde "Widget non disponibile".
  • HTML avanzato — il blocco originale <button> + <script> inline. Identico a ciò che le installazioni precedenti hanno già pubblicato, ma incorpora la selezione corrente nel markup: dopo aver cambiato filtri o stile va ricopiato (lo script di una riga serve sempre le opzioni salvate).

Le guide per piattaforma nella tab danno i passi per CMS (WordPress, Wix/Squarespace, Shopify, HTML personalizzato), e Verifica il tuo embed scarica l'URL di pagina che incolli e riporta se trova la tua public key, i runtime del widget o un link /book/ — riservato ai gestori widget, con rate limit e difese contro richieste verso reti private.

Gli host che creano sessioni embed vengono ricordati (più recenti prima, max 20) e proposti come suggerimenti con un clic sopra la textarea dei domini auth consentiti — finiscono solo nella textarea; nulla persiste finché non salvi. Fidarsi automaticamente di un host visto non sarebbe sicuro, quindi l'aggiunta è sempre esplicita.

generateWidgetSnippet() crea la WidgetIntegration aziendale al primo uso (public key bw_pk_…, secret bw_sk_… — il secret non è mai usato lato client). I campi bottone si risolvono per-campo: evento → tipo evento → azienda → default config/booking-widget.php. Il livello azienda si modifica sotto Avanzate → Stile predefinito bottone — alimenta ogni bottone widget (prenotazioni, richieste, voucher). La pagina welcome della dashboard renderizza il bottone live quando l'azienda non ha ancora prenotazioni.

oEmbed

Le pagine /book/{company} e /book/{company}/{eventType} pubblicizzano GET /oembed?url=… via <link rel="alternate" type="application/json+oembed">. I CMS compatibili con oEmbed trasformano automaticamente un link di prenotazione incollato in un iframe del widget incorporato. Il provider risponde solo per URL sull'host di questa app (/book/* e /w/*), restituisce HTML type: rich che punta a /w/{key}, e limita maxwidth/maxheight a 1200/720. Nota: i CMS che isolano i provider oEmbed non fidati (WordPress avvolge i provider non in whitelist in un frame sandbox dove cookie e form sono bloccati) — usa lì lo snippet script o l'URL iframe /w/.

Filtri e stile

Sotto Avanzate puoi scegliere tipi evento e/o eventi per limitare ciò che il widget mostra (vuoto = tutto). Un singolo evento selezionato apre il widget direttamente su di esso. I filtri confluiscono in ogni formato — URL dello script, URL iframe /w/ e HTML grezzo — quindi genera una volta e poi copia. Sovrascrizione di testo / classi / stile del bottone; l'anteprima live renderizza il bottone reale.

Come funziona l'embed

  1. Il bottone dello snippet chiama POST /api/embed/session con la public_key → restituisce un token bw_et_… da 15 minuti e l'URL iframe /embed?token=….
  2. L'iframe carica /embed attraverso il middleware widget.locale; ConfigureEmbedSession imposta SameSite=None su HTTPS così il cookie di sessione sopravvive negli iframe cross-site.
  3. Se l'integrazione ha allowed_domains, l'header Origin/Referer deve combaciare — il parametro origin non è mai considerato fidato. L'origine dell'app stessa passa sempre: la allowlist blocca gli embedder esterni, mai l'host che serve la pagina.
  4. Quando l'iframe non può portare il cookie di sessione (un embed cross-site su host non-HTTPS non può emettere SameSite=None), le pagine booking/* accettano il fallback embed + embed_parent_origin — validato contro allowed_domains dell'integrazione (o l'origine dell'app) prima di rilassare frame-ancestors.

Ogni render di /embed riuscito marca anche l'origine host validata nella sessione con un timestamp. Le pagine booking/* e gli header di sicurezza si fidano di quel marcatore solo finché è fresco — booking-widget.embed_marker_ttl secondi, sei ore di default (il token iframe bw_et_… scade comunque dopo 15 minuti). Un marcatore mancante, malformato, nel futuro o scaduto fallisce chiuso: la pagina torna all'origine dell'app, ?embed=1 da solo può solo rinfrescare un marcatore già fresco — mai resuscitarne uno morto — e resta il fallback allowlist embed_parent_origin.

Prima di imporre una allowlist in produzione, esegui php artisan widget:allowlist-audit: elenca ogni integrazione attiva con funzionalità widget e allowed_domains ancora vuota (exit 1 se ne esistono, sola lettura), così puoi popolare la lista in anticipo invece di bloccare gli embed attivi.

Link diretti di prenotazione

  • /api/{company}/direct-booking — apre il widget dritto sugli eventi di un'azienda.
  • /api/{eventType}/event-type-booking — preseleziona un tipo evento.
  • Aggiungi ?open=1 a qualsiasi URL /book/... — il widget si apre al caricamento della pagina, senza clic (il "Link di prenotazione immediata" mostrato nelle impostazioni widget).
  • data-area-id sul bottone dello snippet (o area_id su POST /api/embed/session) — deep-link diretto a un'area per le aziende che offrono la prenotazione aree.
  • data-event-type-ids / data-event-ids sul bottone dello snippet (o array event_type_ids / event_ids su POST /api/embed/session, CSV su GET /api/embed/snippet) — whitelist separate da virgola: il calendario del widget mostra solo i tipi/eventi elencati. Gli attributi singolari data-event-type-id / data-event-id restano supportati; data-event-id inoltre fissa e apre quell'evento.
  • data-cal-display sul bottone dello snippet (o oggetto cal_display su POST /api/embed/session) — overlay di visualizzazione per-embed, vedi sotto.

Avvisami quando aprono le date

La pagina pubblica di un tipo evento (/book/{company}/{eventType}) senza date aperte mostra il modulo Avvisami: email più una casella di consenso marketing esplicita e non preselezionata. L'invio crea o aggiorna l'ospite (ricevuta di consenso registrata, tag event-interest) e salva una riga in event_type_interests; la risposta è identica sia che l'email fosse già nota sia di no. Quando una data di quel tipo passa a Pubblicato ed è prenotabile, ogni ospite in attesa riceve una sola email di annuncio con il link per prenotare (consenso ricontrollato all'invio, disiscrizione con un clic). L'invio viene reclamato in modo atomico tramite notified_at, quindi pubblicazioni ripetute non scrivono mai due volte allo stesso ospite; solo un nuovo consenso lo riarma. L'editor del tipo evento mostra quanti ospiti sono in attesa. La cancellazione dell'ospite elimina i suoi interessi.

Attribuzione

POST /api/embed/session riceve già l'URL della pagina ospite (page_url, inviato da widget.js). Alla creazione della sessione i cinque parametri utm_* di quell'URL vengono filtrati in whitelist, troncati e salvati sulla sessione embed; le prenotazioni create dentro l'iframe li ereditano in bookings.utm ({source, medium, campaign, term, content}). Parametri utm_* espliciti sull'URL /booking/confirm vincono sulla copia di sessione — sono il salto più fresco. Le prenotazioni senza nessuno dei due portano utm = null. La sezione dashboard Per fonte riporta le prenotazioni per bookings.source (web/widget/staff/walkin…) più le principali utm_campaign, scopate per azienda.

Regole di visualizzazione

Impostazioni azienda → Visualizzazione calendario (/companies/{company}/edit?tab=display — owner/admin) decide cosa il calendario pubblico elenca e come ogni elemento si legge, per condizione. Condizioni evento: available, sold_out, suspended, closed, draft, unavailable (limiti/figli), upcoming (vendite non aperte), sales_expired (finestra vendite chiusa), ended. Posti/orari accettano available, sold_out, closed, unavailable; le aree le stesse più il toggle closed_day per i giorni la cui programmazione è stata interamente rimossa dalle chiusure.

Ogni regola sceglie mostra/nascondi, apre il pannello (auto riproduce il comportamento precedente — i prenotabili si aprono, i sold-out si aprono solo con la lista d'attesa attiva, i fallimenti per soli figli aprono un pannello in sola lettura, tutto il resto resta chiuso — always/never lo sovrascrivono), e un badge: etichetta di stato, posti rimasti, totale prenotati, prenotati/capacità, percentuale prenotata, testo personalizzato (token {availables} {booked} {capacity} {from} {to}), oppure nessuno. capacity.threshold nasconde i badge "posti rimasti" finché restano più di N posti; il show_bookable_threshold del singolo prenotabile ha comunque priorità.

Le regole si ereditano a cascata azienda → tipo evento → evento (ogni livello sovrascrive per condizione) e il salvataggio emette venue.updated, così i widget aperti si ridipingono live. I vincoli sono solo di visualizzazione: gli elementi nascosti non sono mai serializzati né prenotabili, e nulla qui allenta autorizzazione, capacità o controlli sugli archiviati.

Un singolo embed può adattare la policy con data-cal-display='{"events":{"closed":{"visible":false}}}' — l'overlay si fonde per ultimo nella cascata, quindi vince per ogni chiave che imposta. È sanificato con whitelist: sezioni, condizioni e campi sconosciuti vengono scartati, visible non si può forzare su available, e non può mai aggirare i controlli su tenant, archiviati o capacità.

Modalità aree

Quale calendario renderizza l'iframe dipende dal modello di prenotazione dell'azienda:

  • Le aziende areas ottengono sempre il calendario aree (/widget/areas) — scegli un giorno → un'area → una finestra [from, to).
  • Le aziende ibride (events + Consenti prenotazioni senza evento) renderizzano il calendario eventi unificato, che offre anche la scelta area "senza evento"; un deep-link data-area-id apre il calendario aree direttamente su quell'area.
  • Quando almeno un'area ha una forma disegnata, entrambi i widget mostrano la mappa del locale come selettore delle aree (forme toccabili, aree non disegnate su una riga di chip); i tavoli sul floor sono dipinti come decorazione. Senza nulla di disegnato, i clienti vedono la lista semplice. Dentro le prenotazioni di evento con posti la stessa mappa funge anche da selettore delle posizioni — i posti prendono la forma della loro area madre — incluse le aziende solo-eventi che attivano area_map_picker.

Vedi Prenotazione aree per le impostazioni a livello di area che lo governano.

Voucher vendibili

Le aziende possono vendere voucher regalo dal proprio sito — Impostazioni azienda → tab Voucher (?tab=vouchers) configura gli importi predefiniti, il range dell'importo libero, i giorni di validità, il link alle condizioni e mostra lo storico acquisti. Abilitare lo shop sblocca la modalità voucher nel builder embed unificato (tab Widget prenotazioni, selettore → Voucher regalo): un bottone data-promo-voucher che apre lo shop voucher nello stesso overlay (POST /api/embed/session con mode: 'voucher'). Testo/classi/stile del bottone persistono nel meta dell'integrazione sotto buttons.voucher — i campi vuoti ereditano lo stile predefinito aziendale del bottone.

Il compratore sceglie l'importo, inserisce la propria email, opzionalmente lo invia come regalo (email destinatario + messaggio), e paga tramite l'account Stripe connesso dell'azienda — stessa meccanica destination-charge delle prenotazioni. Su checkout.session.completed il sistema crea un PromoCode whitelist (source='purchase', balance = importo) e lo invia via email al compratore o al destinatario regalo.

I codici voucher sono multi-uso: ogni riscatto decrementa balance sotto lock della riga promo, quindi il valore residuo continua a funzionare su prenotazioni successive fino a esaurimento. Acquisto scaduto/rimborsato → status='expired'/'refunded'; un rimborso Stripe completo disattiva il codice creato.

Voucher mirati: selezionare eventi o tipi di evento nel builder in modalità voucher incorpora data-event-id/data-event-ids nel bottone voucher — ogni voucher acquistato tramite esso resta vincolato a quella selezione. Lo shop mostra la limitazione prima del pagamento, il codice creato rifiuta qualsiasi altra prenotazione (errore di validazione per i clienti E per le approvazioni staff), e la mail di consegna dichiara l'ambito. data-area-id viene ignorato ai fini del targeting. Gli stessi selettori esistono nell'editor codici promo per i codici manuali.

Reinvio + card stampabile: ogni riga pagata dello storico acquisti ha un'azione Reinvia che rispedisce la mail del codice al titolare (destinatario regalo se presente, altrimenti acquirente). La mail di consegna linka anche una gift card stampabile brandizzata su GET /voucher/{code}/card — logo, importo, saldo residuo, destinazione e scadenza, con bottone stampa/"salva come PDF". Il codice stesso è la credenziale della pagina (viaggia già nella mail); la rotta è rate-limited e solo i voucher acquistati si risolvono — i codici promo staff danno 404.

Widget lead-gen: richieste e raccolta

Il selettore nella tab Widget prenotazioni genera anche le superfici lead-gen — stessi formati embed (script / iframe / HTML), stessa pipeline di sessione, stessa allowlist di origini:

  • Richiesta evento privato (mode: 'inquiry', trigger data-inquiry) apre il form lead del locale dentro /embed con source=widget marcato al mount. I parametri calendario (event_id, area_id, cal_display, …) sono ignorati. I lead arrivano nell'inbox lead.
  • Raccolta email (mode: 'capture', trigger data-capture) apre il form iscrizione con consenso dentro /embed. Le iscrizioni fanno upsert nel guestbook con semantica primo-consenso-vince.

Entrambi i form mantengono gli URL pubblici diretti — /inquiry/{company} e /capture/{company} — per i link diretti. Una volta configurati gli allowed_domains, quelle pagine possono essere incorporate solo dai siti consentiti (frame-ancestors); senza lista configurata restano liberamente incorporabili come prima.

Interruttori per superficie

In Avanzate → Superfici widget ogni modalità ha un toggle. Spegnendola la si scrive in meta.disabled_modes dell'integrazione e ogni entrypoint la rifiuta all'istante — generazione sessioni, snippet/snippet.js, redirect /w/, render /embed già attivi e le pagine pubbliche dirette. Le altre modalità non vengono toccate; riattivandola il servizio riprende subito.

Link di prenotazione per canale

La tab widget prenotazioni mostra anche i deep link per canale: URL di prenotazione pronti da incollare già taggati con sorgente/medium UTM, così l'attribuzione sorgente su ogni prenotazione divide il traffico per canale — Google Business Profile, Instagram, Facebook, più un campo sorgente libera che normalizza ciò che digiti. Un tag campagna opzionale si applica a ogni riga. Copia il link nel campo "Prenota online" del Profilo dell'attività, nella bio di Instagram o nel pulsante "Prenota ora" di Facebook e le prenotazioni portano la sorgente automaticamente — nessun embed necessario.

Dentro il widget

I clienti vedono gli eventi pubblicati, dentro la finestra di prenotazione e non sold-out (quelli sold-out offrono la waitlist quando abilitata). Lingua e tema si cambiano dentro l'iframe. Gli eventi di aziende private sono prenotabili solo dai membri azienda.

Permessi

La gestione dello snippet è owner/admin via impostazioni azienda. Il widget stesso è pubblico — chiunque abbia l'URL embed può navigare e prenotare (salvo il flag private dell'azienda). Un utente loggato a un'azienda diversa vede il widget esattamente come un visitatore anonimo — nessun permesso staff, nessuna prenotazione forzata — e la sua azienda attiva non cambia mai.

Cookies und Datenschutz

Wir verwenden notwendige Cookies, um die Sicherheit und den ordnungsgemäßen Betrieb der Anwendung zu gewährleisten. Optionale Cookies werden nur mit Ihrer Einwilligung verwendet.

Lesen Sie die Datenschutzerklärung Lesen Sie die Cookie-Richtlinie

Unverzichtbar

Unverzichtbare Cookies sind für das Funktionieren der Website erforderlich und können nicht deaktiviert werden.

Immer eingeschaltet

Funktional

Funktionale Cookies ermöglichen erweiterte Funktionen und eine individuelle Anpassung, beispielsweise indem sie Ihre Sprache und Ihre Einstellungen speichern.

Analytik

Analytics-Cookies helfen uns zu verstehen, wie Besucher mit der Anwendung interagieren, damit wir sie verbessern können.

Marketing

Marketing-Cookies werden verwendet, um Besucher über verschiedene Websites hinweg zu verfolgen und ihnen relevante und ansprechende Werbung anzuzeigen.