1. Che cos’è la sandbox e perché il tuo widget è in gabbia
Quando ChatGPT mostra il tuo widget, lo rende non come un normale <iframe src="https://il-tuo-sito">. Il widget viene eseguito in una «sandbox» controllata — un iframe isolato con origin separato e impostazioni di sicurezza rigide.
Tecnicamente appare più o meno così:
flowchart TD
User["Utente in ChatGPT"]
Chat["ChatGPT UI + modello"]
Iframe["Il tuo widget
iframe in sandbox"]
MCP["Il tuo MCP / backend"]
User --> Chat
Chat -->|chiamata dello strumento| MCP
MCP -->|structuredContent + _meta| Chat
Chat -->|window.openai.*| Iframe
Iframe -->|callTool / follow-up| Chat
Chat --> MCP
Il tuo codice viene eseguito solo dentro questo iframe e l’accesso al resto del mondo passa attraverso un API strettamente controllata fornita dall’host (ChatGPT). Il widget non deve:
- rompere ChatGPT stesso (DOM, stili, performance);
- violare la privacy dell’utente;
- accedere alla rete senza controllo.
Da qui derivano le limitazioni chiave della sandbox.
Isolamento di DOM e origin
Il widget vive su un dominio speciale della sandbox (per esempio, https://sandbox-apps.oaiusercontent.com), con l’attributo sandbox sull’iframe. Questo significa che:
- non puoi accedere a window.parent o al document di ChatGPT: otterrai un SecurityError;
- operazioni cross-domain come postMessage sono controllate dall’host;
- qualunque tentativo di «aggiustare l’interfaccia di ChatGPT con un CSS» è destinato a fallire.
Rete e limitazioni CSP
Il browser e la politica CSP dell’host limitano l’accesso alla rete per il tuo widget:
- il metodo fetch ha accesso solo ai domini nella whitelist, che devono passare una revisione;
- i domini accessibili dal widget vanno dichiarati esplicitamente tramite openai/widgetCSP nelle risposte MCP; altrimenti le richieste verranno bloccate;
- la via consigliata per tutto ciò che è serio è non fare chiamate di rete dal widget, ma passare al backend tramite strumenti MCP e callTool (ne parleremo meglio nel Modulo 4).
In pratica: pensa al widget come a un sottile strato UI. Parla con ChatGPT e con il tuo server tramite canali ben definiti, non come una SPA che vive liberamente su Internet.
Storage e risorse
Gli storage locali (localStorage, sessionStorage) sono disponibili, ma i cookie no. Tienilo presente nello sviluppo dell’applicazione. Memoria e CPU sono limitate: se decidi di calcolare tutti i numeri primi fino a un miliardo dentro il widget, l’host ha pieno diritto di terminare il tuo iframe.
Ne consegue: niente calcoli pesanti e nessuna «cache» di lunga durata nel widget. La logica complessa deve stare lato server, non in un componente React.
2. window.openai: il ponte tra widget e ChatGPT
Perché il widget possa sapere qualcosa (risultati dello strumento, modalità di visualizzazione, locale, stato), ChatGPT durante l’inizializzazione inserisce nella finestra dell’iframe un oggetto globale: window.openai.
Non è codice tuo e non è un pacchetto npm, ma un host object fornito direttamente dalla piattaforma di IA. Sotto il cofano si basa su eventi e messaggi tra host e iframe, ma non serve pensarci troppo. Ricorda però alcune cose.
Chi e quando crea window.openai
window.openai compare solo:
- all’interno dell’iframe che ChatGPT ha creato per il tuo widget;
- quando il template HTML viene servito con il mimeType corretto (text/html+skybridge) e ha superato tutti i controlli.
Hai già visto questo tipo nel modulo su HelloWorld App: è quello che la pagina del widget restituisce al posto di text/html.
Se apri semplicemente la pagina del widget direttamente nel browser, allora:
console.log(window.openai); // undefined
ed è normale. Quindi nel codice del widget conviene sempre verificare che l’oggetto esista, se prevedi una modalità «standalone» per lo sviluppo locale o per Storybook.
Esempio semplice (non definitivo, solo illustrazione):
if (typeof window !== "undefined" && (window as any).openai) {
console.log("We are inside ChatGPT sandbox!");
}
Asincronia dell’inizializzazione
Sotto il cofano, ChatGPT aggiorna window.openai man mano che arrivano nuovi dati (nuovo toolOutput, cambio di displayMode ecc.), usando l’evento interno openai:set_globals.
Quindi i «valori» al suo interno non sono statici: il modello di IA può chiamare uno strumento MCP, il backend restituirà nuovi structuredContent e window.openai.toolOutput cambierà proprio sotto il tuo componente React.
Ne derivano due raccomandazioni:
- Non creare snapshot «alla cieca» del tipo const toolOutput = window.openai.toolOutput una volta all’inizio pensando che siano eterni. Lo stesso widget può essere riutilizzato da ChatGPT.
- Usa lo strato di hook (tra poco), che sa iscriversi ai cambiamenti.
3. Anatomia di window.openai: dati, API e contesto
La documentazione ufficiale fornisce una tabella compatta con campi e metodi di window.openai. Riorganizziamola in modo più «umano».
Campi e metodi principali
window.openai = {
// State & data
toolInput, // JSON: parametri che l'IA ha passato al tuo MCP tool
toolOutput, // JSON: parametri che il tuo MCP tool ha restituito all'IA
toolResponseMetadata, // Risposta del MCP tool: parte di _meta: {...}
widgetState, // Puoi leggere lo stato salvato del widget
setWidgetState, // Puoi salvare lo stato del tuo widget qui
// Runtime APIs
callTool, // Puoi chiamare un MCP tool
sendFollowUpMessage, // Inviare di nascosto un messaggio all'IA in chat: inizierà a rispondere.
requestDisplayMode, // Passare il widget in un'altra modalità: fullscreen, pip, inline
requestModal, // Trasformare il widget in una finestra modale.
requestClose, // Chiude il widget. Chiusa la modale, torna a widget.
requestCheckout, // Apre una finestra modale per il pagamento. Il server deve implementare ACP
notifyIntrinsicHeight, // Notifica il cambiamento dell'altezza del widget
openExternal, // Aprire un link in una nuova finestra.
// Context
theme, // Tema scuro o chiaro
displayMode, // Modalità di visualizzazione corrente del widget, può differire da requestDisplayMode
maxHeight, // Altezza massima consentita del widget
safeArea, // "Area sicura di rendering" - rilevante per telefoni con "notch"
view,
userAgent, // userAgent del browser
locale // locale del browser
}
La stessa cosa in tabella:
| Categoria | Proprietà / metodo | A cosa serve |
|---|---|---|
| State & data | |
Argomenti con cui è stato chiamato lo strumento. Sola lettura. |
| State & data | |
Il tuo structuredContent dalla risposta MCP. Ciò che vede il widget e il modello. |
| State & data | |
_meta dalla risposta. Visibile solo al widget, il modello non lo legge. |
| State & data | |
Istanza dello stato UI che ChatGPT conserva tra i render del widget. |
| State & data | |
Salvare sincronicamente una nuova istanza di widgetState. |
| Function | |
Chiamare uno strumento MCP dal widget. |
| Function | |
Chiedere a ChatGPT di inviare un messaggio in chat a nome del widget. Inizierà a rispondere. |
| Function | |
Richiedere all’host inline / fullscreen / pip. |
| Function | |
Richiedere l’apertura di una finestra modale. |
| Function | |
Segnalare che l’altezza del contenuto è cambiata. |
| Function | |
Apre il dialogo di pagamento tramite protocollo ACP. |
| Function | |
Aprire un link esterno nel browser dell’utente. |
| Context | |
Segnali d’ambiente: tema, modalità, altezza disponibile, locale ecc. |
Non è necessario memorizzare subito tutto ciò che c’è in questa tabella: considerala come una «mappa del territorio». Ora analizziamola non come «manuale», ma come farebbe una persona normale.
toolInput e toolOutput: da dove arrivano i dati
Quando il modello decide di chiamare il tuo strumento, forma degli argomenti JSON. Questi argomenti:
- arrivano al server MCP come input al relativo handler;
- arrivano contemporaneamente a window.openai.toolInput nel widget.
Dopo l’esecuzione dello strumento, il server restituisce:
- structuredContent — dati strutturati per l’UI;
- _meta — dati privati solo per il widget;
- content — testo per il modello stesso, così che possa «raccontare» all’utente cosa è successo.
structuredContent diventa window.openai.toolOutput, e _meta diventa window.openai.toolResponseMetadata.
Mini-esempio (vanilla JS, senza React):
const root = document.getElementById("root");
// Si può usare in sicurezza l'operatore nullish
const gifts = window.openai.toolOutput?.gifts ?? [];
root.textContent = `Regali trovati: ${gifts.length}`;
widgetState e setWidgetState: la memoria del widget
widgetState è ciò che la piattaforma è disposta a ricordare del tuo UI tra i render e perfino tra diversi turni di dialogo.
Esempi naturali per widgetState:
- il regalo selezionato;
- l’ordinamento corrente (per prezzo / per popolarità);
- il numero di pagina nell’elenco.
Non naturali:
- la risposta grezza di un’API esterna;
- un’immagine in base64;
- token segreti.
Ricorda due cose:
- widgetState viene archiviato e passato al modello insieme al contesto, quindi non metterci nulla di sensibile.
- Il volume è limitato (circa 4 mila token), quindi non farne un mini database.
Esempio d’uso semplicissimo (in modo diretto, senza hook, in vanilla JS):
const current = window.openai.widgetState ?? { selectedGiftId: null };
function selectGift(id) {
window.openai.setWidgetState({ ...current, selectedGiftId: id });
}
Nel codice reale lo incapsuleremo negli hook di React.
Runtime API: callTool, sendFollowUpMessage e simili
Questi metodi permettono al widget non solo di «rendersi», ma anche di interagire con il dialogo e il server.
Alcuni scenari tipici:
- callTool("search_gifts", { budget: 50 }) — l’utente ha cliccato il pulsante «Modifica budget», chiami il server e aggiorni l’UI;
- sendFollowUpMessage({ prompt: "Mostra altre idee più costose" }) — invece di chiedere all’utente di scrivere a mano, aggiungi un pulsante follow-up che crea un nuovo messaggio in chat;
- requestDisplayMode({ mode: "fullscreen" }) — se la modalità inline è stretta, il widget può chiedere gentilmente a ChatGPT di andare a schermo intero;
- openExternal({ href: "https://myshop.com/checkout?giftId=123" }) — inviare l’utente a un sito esterno (checkout, profilo ecc.) tramite un canale controllato.
Tutto passa «via cavo» attraverso ChatGPT, non direttamente su Internet.
Contesto dell’ambiente: tema, modalità, altezza, locale
Campi come theme, displayMode, maxHeight, locale ti danno il polso dell’ambiente in cui vive il widget.
Per esempio:
const theme = window.openai.theme; // "light" o "dark"
const mode = window.openai.displayMode; // "inline" | "fullscreen" | "pip"
const maxH = window.openai.maxHeight; // altezza disponibile
const locale = window.openai.locale; // "en-US", "de-DE", ...
Con questi segnali puoi:
- adattare colori e spaziature al tema;
- cambiare il layout a seconda della modalità (inline vs fullscreen);
- localizzare le etichette dell’UI in base alla lingua dell’utente (ci sarà un modulo dedicato).
La piattaforma ti dà segnali su spazio disponibile, tema e locale. È sensato usarli tramite useOpenAIGlobal, useDisplayMode, useMaxHeight e altri hook, così che il widget risulti «nativo» in ChatGPT.
4. Hook sopra window.openai: non toccare l’oggetto globale a mano
L’accesso diretto a window.openai è comodo per un prototipo, ma presto rende il codice caotico: sottoscrizioni a eventi, controlli su undefined, wrapper ripetuti. Per questo nel template Next.js per l’Apps SDK c’è un set di hook React pronti che nascondono i dettagli e rendono tutto reattivo.
Un tipico indice degli hook appare così:
// app/hooks/openai/index.ts
export { useCallTool } from "./use-call-tool";
export { useSendMessage } from "./use-send-message";
export { useOpenExternal } from "./use-open-external";
export { useRequestDisplayMode, useRequestModal, useRequestClose } from "./use-request-display-mode";
export { useRequestCheckout } from "./use-request-checkout";
// State hooks
export { useDisplayMode } from "./use-display-mode";
export { useWidgetProps } from "./use-widget-props";
export { useWidgetState } from "./use-widget-state";
export { useOpenAIGlobal } from "./use-openai-global";
export { useMaxHeight } from "./use-max-height";
export { useIsChatGptApp } from "./use-is-chatgpt-app";
I nomi e il percorso esatto possono variare nel tuo template, ma l’idea è sempre la stessa: invece di window.openai.* usi degli hook. Vediamo i principali.
useWidgetProps: input e output dello strumento
useWidgetProps di solito restituisce un oggetto con i dati necessari al widget: toolInput, toolOutput, toolResponseMetadata e talvolta flag aggiuntivi come isLoading.
Esempio:
import { useWidgetProps } from "../hooks/openai";
type Gift = { id: string; title: string; price: number };
export function GiftList() {
const { toolOutput } = useWidgetProps<{ gifts: Gift[] }>();
const gifts = toolOutput?.gifts ?? [];
if (!gifts.length) {
return <div>Al momento non ci sono opzioni di regalo.</div>;
}
return (
<ul>
{gifts.map((g) => (
<li key={g.id}>{g.title} — ${g.price}</li>
))}
</ul>
);
}
Nessun window.openai nel codice del componente — ed è un bene.
useWidgetState: «wrapper reattivo» sopra widgetState
useWidgetState permette di lavorare con widgetState come con un normale stato React: ottieni [state, setState], e l’hook sincronizza sotto il cofano con window.openai.widgetState e setWidgetState.
Esempio:
import { useWidgetState } from "../hooks/openai";
type UiState = { selectedGiftId: string | null };
export function SelectedGiftIndicator() {
const [uiState, setUiState] = useWidgetState<UiState>(() => ({
selectedGiftId: null,
}));
if (!uiState?.selectedGiftId) {
return <div>Nessun regalo selezionato.</div>;
}
return (
<div>
Hai selezionato il regalo con id={uiState.selectedGiftId}
<button onClick={() => setUiState({ selectedGiftId: null })}>
Reimposta
</button>
</div>
);
}
Dopo il click, setUiState non solo aggiorna lo stato React, ma salva anche il nuovo stato lato ChatGPT.
useOpenAIGlobal: accesso a qualsiasi campo di window.openai
Se serve accedere a un singolo campo globale (per esempio tema o modalità), c’è l’hook universale useOpenAIGlobal(key). Si sottoscrive all’evento openai:set_globals e restituisce sempre il valore aggiornato.
Esempio:
import { useOpenAIGlobal } from "../hooks/openai";
export function ThemeAwareBlock() {
const theme = useOpenAIGlobal<"light" | "dark">("theme");
const background = theme === "dark" ? "#222" : "#fff";
const color = theme === "dark" ? "#fff" : "#000";
return <div style={{ background, color }}>Rispetto il tema di ChatGPT</div>;
}
useCallTool, useSendMessage, useOpenExternal e altri
- useCallTool(name) — restituisce una funzione che chiama lo strumento MCP con quel nome. È un wrapper sopra callTool.
- useSendMessage() — incapsula sendFollowUpMessage, così che il widget possa iniziare messaggi.
- useOpenExternal() — helper comodo attorno a openExternal({ href }).
- useRequestDisplayMode() e useRequestModal() — wrapper per richiedere cambio modalità / apertura modale.
Esempio base del mini-widget GiftGenius, che usa quasi tutto insieme:
import {
useWidgetProps,
useWidgetState,
useCallTool,
useSendMessage,
useOpenExternal,
} from "../hooks/openai";
type Gift = { id: string; title: string; url: string; price: number };
export function GiftWidget() {
const { toolOutput } = useWidgetProps<{ gifts: Gift[] }>();
const gifts = toolOutput?.gifts ?? [];
const [ui, setUi] = useWidgetState<{ selectedId: string | null }>(() => ({
selectedId: null,
}));
const callSearch = useCallTool("search_gifts");
const sendMessage = useSendMessage();
const openExternal = useOpenExternal();
if (!gifts.length) {
return <div>Non ci sono ancora idee. Prova a chiedere a GPT di aggiornare i risultati.</div>;
}
return (
<div>
{gifts.map((g) => (
<button
key={g.id}
style={{
display: "block",
fontWeight: ui?.selectedId === g.id ? "bold" : "normal",
}}
onClick={() => setUi({ selectedId: g.id })}
>
{g.title} — ${g.price}
</button>
))}
<div style={{ marginTop: 12 }}>
<button
onClick={() =>
sendMessage({ prompt: "Mostra regali più costosi degli attuali." })
}
>
Chiedi altre idee
</button>
<button
onClick={async () => {
await callSearch({ budget: 200 });
}}
>
Aggiorna con budget di $200
</button>
{ui?.selectedId && (
<button
onClick={() =>
openExternal({
href: `https://giftgenius.example.com/checkout?id=${ui.selectedId}`,
})
}
>
Vai all'acquisto
</button>
)}
</div>
</div>
);
}
Questa pagina è ancora grezza (nei moduli successivi miglioreremo UX, gestione degli errori ecc.), ma illustra già l’approccio: nessun accesso diretto a window.openai, solo hook.
5. Pratica: esploriamo la sandbox e window.openai
Per capire che cos’è «un widget non come un normale sito», è utile fare un paio di esercizi.
Esercizio: «Esplora l’ambiente»
Prendi il tuo attuale app/page.tsx nel widget e aggiungi al primo render un semplice effetto:
import { useEffect } from "react";
import { useIsChatGptApp } from "../hooks/openai";
export default function Root() {
const isChatGpt = useIsChatGptApp();
useEffect(() => {
if (typeof window !== "undefined") {
console.log("window.origin =", window.origin);
console.log("window.openai =", (window as any).openai);
}
}, []);
return (
<main>
<h1>GiftGenius widget</h1>
<p>Eseguito dentro ChatGPT: {String(isChatGpt)}</p>
</main>
);
}
Apri DevTools: o direttamente nella finestra di ChatGPT (tramite il viewer integrato del tunnel, se lo consente), oppure nel browser locale aprendo la pagina direttamente. In entrambi i casi confronta:
- in un browser normale, isChatGptApp sarà false e window.openai molto probabilmente undefined;
- quando avviato tramite ChatGPT vedrai un oggetto con campi come toolInput, toolOutput, theme ecc.
È una buona intuizione: lo stesso codice React si comporta in modo diverso a seconda dell’ambiente, ed è proprio per questo che esistono gli hook.
Esercizio: «Mostra tutto ciò che offre la piattaforma»
Aggiungi un componente temporaneo per il debug:
import { useWidgetProps, useOpenAIGlobal } from "../hooks/openai";
export function DebugPanel() {
const { toolInput, toolOutput, toolResponseMetadata } = useWidgetProps();
const theme = useOpenAIGlobal("theme");
const displayMode = useOpenAIGlobal("displayMode");
return (
<pre style={{ fontSize: 10, maxHeight: 200, overflow: "auto" }}>
{JSON.stringify(
{ toolInput, toolOutput, toolResponseMetadata, theme, displayMode },
null,
2
)}
</pre>
);
}
E inserisci temporaneamente <DebugPanel /> sotto l’UI principale. Vedrai chiaramente:
- quali campi arrivano da MCP in toolOutput;
- cosa c’è in _meta (per esempio, locale, userLocation e altro);
- come cambia displayMode quando espandi il widget.
Poi puoi rimuovere questo componente o lasciarlo attivabile tramite un flag tipo DEBUG_WIDGET.
6. Relazioni: ChatGPT ↔ widget ↔ MCP/server
Per non considerare il widget come l’«attore principale» del sistema, è utile fissare di nuovo i ruoli.
- L’utente scrive un messaggio: «Scegli un regalo per la ragazza, budget 50$».
- Il modello di ChatGPT decide di chiamare il tuo strumento MCP search_gifts con gli argomenti { recipient: "girlfriend", budget: 50 }.
- Il server MCP esegue la logica di business e restituisce:
- content con una breve descrizione per il modello;
- structuredContent con l’array di regali;
- _meta con dettagli tecnici (per esempio, source e valuta).
- ChatGPT:
- mostra all’utente un messaggio testuale («Ho trovato alcune opzioni…»);
- crea l’iframe del widget e vi passa structuredContent e _meta tramite window.openai.toolOutput e toolResponseMetadata.
- Il tuo widget:
- renderizza l’UI in base a toolOutput;
- durante le interazioni chiama callTool o invia follow-up;
- Il modello decide poi come usare i risultati di queste azioni.
Questo porta a una conclusione importante: il widget non è mai l’unico padrone del processo. È lo strato UI che vive nell’ecosistema formato dal modello e dal server MCP. Le cose complesse (autorizzazione, accesso a dati privati, logica di business seria) devono restare lato server. Il widget è responsabile di un’interfaccia comoda e di un’interazione accurata con l’utente.
7. Policy e regole del gioco nella sandbox
Tutta questa costruzione con iframe isolato e window.openai esiste per motivi di sicurezza e privacy. Le guide ufficiali di OpenAI sottolineano alcuni principi.
Primo, minimizzazione dei dati. Non devi cercare di estrarre quante più PII (personally identifiable information) possibile dall’utente tramite il widget e portarle da te. Tutto ciò che è davvero necessario deve essere descritto chiaramente negli strumenti, e il modello e il livello di sicurezza valuteranno attentamente tali chiamate.
Secondo, divieto di tracciamento nascosto e fingerprinting. Non costruire sistemi per «spiare» il dispositivo dell’utente, raccogliere impronte del browser o aggirare le limitazioni. Parametri come userAgent, userLocation ecc. sono suggerimenti per l’UX, non per l’autenticazione o l’identificazione.
Terzo, tutto ciò che inserisci in structuredContent, _meta, widgetState in qualche forma è visibile all’utente o può esserlo a un revisore dello Store. Pertanto:
- non mettere lì API key, token, password o segreti amministrativi;
- progetta lo stato del widget in modo che l’utente non si sorprenda a vederlo nei log o nel debug.
Quarto, chiamate di rete. Richieste dirette dal widget verso API di terze parti sono ammesse solo verso una lista stretta di domini e in scenari non sensibili. Quando si parla di denaro, account, dati personali — tutto deve passare attraverso MCP/backend.
8. Errori tipici nel lavoro in sandbox e con window.openai
Errore n. 1: pensare che il widget sia «un normale sito in iframe».
Per abitudine i neofiti provano ad accedere a window.parent, a modificare gli stili di ChatGPT o a usare localStorage come sempre. Nella sandbox questo o non funziona, o è instabile: l’origin è diversa, lo storage è isolato, l’accesso al DOM è bloccato. Accetta di vivere in un ambiente controllato e comunica con l’host solo tramite window.openai e gli hook.
Errore n. 2: toccare window.openai direttamente dappertutto.
Codice del tipo window.openai.toolOutput in dieci componenti porta a un’app difficile da debuggare. Inoltre devi gestire da solo eventi, asincronia e controlli di undefined. È molto più affidabile usare subito useWidgetProps, useWidgetState, useOpenAIGlobal e altri hook, che già incapsulano openai:set_globals e sincronizzano lo stato.
Errore n. 3: archiviare in widgetState di tutto (soprattutto segreti).
Talvolta viene voglia di infilarci per sicurezza un enorme oggetto con risultati di API o perfino un access token. Il risultato è un contesto che cresce, peggiora il lavoro del modello e viola requisiti basilari di sicurezza. widgetState deve essere piccolo, contenere solo segnali UI e mai dati confidenziali.
Errore n. 4: provare ad andare su Internet direttamente dal widget.
Le chiamate fetch("https://api.superbank.com/...") dalla sandbox quasi sicuramente incontreranno CORS e, anche se configuri tutto alla perfezione, sarà insicuro e difficile da gestire. Tutto ciò che riguarda account reali, denaro e dati personali va implementato come strumenti MCP e chiamato tramite callTool o attraverso la parte server.
Errore n. 5: contare sulla stabilità di window.openai fuori da ChatGPT.
A volte gli sviluppatori provano ad avviare il widget come SPA separata e non aggiungono controlli sul fatto che window.openai possa essere undefined. In dev questo si traduce in crash «Cannot read properties of undefined». Usa useIsChatGptApp, i controlli su typeof window !== "undefined" e un fallback UI per i casi in cui il widget non esista.
Errore n. 6: ignorare il contesto dell’ambiente (theme, displayMode, maxHeight, locale).
Puoi certo impostare un’altezza fissa di 2000px, tema scuro sempre e progettare per desktop — ma l’esperienza per l’utente sarà strana. La piattaforma ti fornisce segnali su spazio disponibile, tema e locale: usali tramite useOpenAIGlobal, useDisplayMode, useMaxHeight ecc., così che il widget sembri «di casa» in ChatGPT.
Errore n. 7: provare ad «aggirare» la policy tramite script di terze parti.
A volte viene la tentazione di caricare un tracker, un bundle JS esterno o eseguire codice da un dominio terzo «in silenzio». La sandbox e le policy CSP esistono proprio per evitarlo: gli script di terze parti vengono bloccati e i tentativi di aggirare il sistema portano direttamente al rifiuto della tua App nello Store.
GO TO FULL VERSION