Skip to content

Embeds e white-label

Qualquer jornal, ONG ou microsite governamental pode exibir um dado real e citado do Futuros — o valor mais um chip de fonte com deep link para a fonte primária — com um único <iframe>. O contrato de honestidade viaja com o embed: um embed nunca mostra um número sem sua procedência.

Três rotas de widget mais um builder:

RotaRenderiza
/embed/statUma estatística citada — valor grande + unidade, chip de delta com sinal, chip de fonte, marca
/embed/chartO mesmo indicador como um pequeno gráfico de linha (último ponto rotulado)
/embed/boardUma grade responsiva com vários quadros stat/chart — um dashboard inteiro em um iframe
/incrustarA UI do builder em ES — escolha as opções, veja a prévia ao vivo, copie o snippet

Todas as rotas de embed são embutíveis cross-origin: o vercel.json define Content-Security-Policy: frame-ancestors * em /embed/(.*) (o resto do site usa X-Frame-Options: SAMEORIGIN). O chrome do app (navegação, onboarding) é desativado sob /embed, então o widget pinta apenas a si mesmo.

/embed/stat e /embed/chart

Parâmetros de query compartilhados:

ParâmetroValoresPadrãoNotas
paramslug do pilar (salud, educacion, …)saludqual pilar
isoISO3 (MEX, BRA, …) ou LATAMMEXconvertido para maiúsculas automaticamente; LATAM renderiza o agregado regional ("América Latina y el Caribe")
indicatorid do indicadorprimeiro indicador da célulaescolha uma métrica específica
themelight | darkdark
langes | en | ptesstrings trilíngues completas + rótulos/unidades de métricas localizados
accentcor hex #RGB#RRGGBBAAazul Oxford (#11457e claro / #6496d5 escuro)acento white-label (deve casar com /^#[0-9a-fA-F]{3,8}$/); sobrescreve tanto o acento quanto a cor de delta positivo

O valor, o delta (vs. a média de 3 anos), a unidade e o chip de fonte vêm do mesmo payload estático de célula que o app usa; o chip de fonte aponta para a fonte primária do indicador e a marca aponta de volta para a célula viva do atlas.

Quatro mecânicas por trás desse parágrafo (todas em src/routes/_embed-shared.tsx):

  • Gate somente-estático. fetchParameter() carrega a célula gerada no build /data/parameter-cache/<param>__<ISO>.json e reporta source: "static" | "mock" mais status: ready | not_generated | quarantined. Em um cache miss, o app principal pinta um mock determinístico para manter o layout vivo; o embed trata qualquer coisa que não seja source:"static" — ou que seja not_generated — como sem dados, porque um valor mock dentro de um iframe de terceiro seria um número fabricado vestindo um chip de fonte real.
  • Ordem de resolução do chip de fonte. Três passos, o primeiro acerto vence: campos inline no indicador (source, source_url, vintage_year) → a linha citations[] do próprio payload casada por citation_id → o registro de fontes (inferSourceKey(citation_id) → metadados da instituição → template de URL deepLinkFor()). O passo do registro é a mesma maquinaria de syntheticCitation(): o chip pode ser reconstruído apenas a partir do id, e somente um id que não mapeia para nenhuma instituição conhecida não produz nada.
  • Rótulos. Os payloads gerados no build carregam apenas rótulos/unidades canônicos em ES; ?lang=en|pt os sobrepõe a partir do registro de métricas gerado no build, carregado de forma assíncrona e cacheado em nível de módulo. O texto ES pinta imediatamente e permanece se esse fetch nunca resolver, e o embed honra ?lang= exatamente — ao contrário do app principal, nunca recai na preferência de idioma armazenada do visitante.
  • A cor do delta é sensível à direção. O chip colore pelo good_direction do indicador (up / down / neutral): um valor em queda de uma métrica onde cair é bom renderiza como bom; neutral renderiza cinza.

/embed/chart exige adicionalmente uma series não vazia no indicador — um valor citado sem histórico renderiza o estado sem-dados, nunca um gráfico vazio. O último ponto é marcado com um ponto de referência e repetido como valor de destaque.

Embed mínimo de estatística:

html
<iframe
  src="https://futuros.xyz/embed/stat?param=salud&iso=MEX&theme=light&lang=pt"
  width="320" height="180" style="border:0" loading="lazy"
  title="Futuros — Saúde, México"></iframe>

Embed de gráfico white-label (acento customizado, português, indicador específico):

html
<iframe
  src="https://futuros.xyz/embed/chart?param=educacion&iso=BRA&indicator=se_xpd_totl_gd_zs&theme=dark&lang=pt&accent=%23004b87"
  width="360" height="240" style="border:0" loading="lazy"
  title="Futuros — Gasto em educação, Brasil"></iframe>

Note o # codificado na URL (%23). Os tamanhos sugeridos seguem o builder /incrustar: stat 320×180, chart 360×240.

/embed/board — dashboard multi-quadro

Um único iframe renderiza uma grade responsiva e tematizada de quadros stat/chart. Um parceiro (BID / CAF / CELAC) insere um único iframe e recebe um dashboard inteiro, white-label, sem mudança de código.

Parâmetros:

ParâmetroValoresPadrãoNotas
panelskind:param:iso[:indicator] separados por vírgulakind = stat | chart; até 12 quadros
themelight | darkdarktematiza o shell e cada quadro
accentcor hexrepassado a cada quadro
brandtexto livreFuturossubstitui a marca; com um brand customizado a atribuição no rodapé lê "powered by Futuros ↗", caso contrário lê "futuros.xyz ↗"
langes | en | ptesencaminhado a cada quadro

Cada spec de quadro é kind:param:iso[:indicator] — p. ex. stat:salud:MEX ou chart:educacion:BRA:se_xpd_totl_gd_zs. O board monta cada quadro como um iframe same-origin de /embed/stat ou /embed/chart, encaminhando theme, lang e accent.

O parsing degrada campo a campo, nunca o board inteiro: um kind desconhecido vira stat, um param vazio vira salud, um iso vazio vira MEX (sempre em maiúsculas), e qualquer coisa além de 12 quadros é truncada silenciosamente. Os quadros renderizam como iframes de altura fixa (stat 160 px, chart 220 px) em uma grade auto-fill com coluna mínima de 260 px, então o board reflui com a largura da página hospedeira.

Um dashboard de país white-label:

html
<iframe
  src="https://futuros.xyz/embed/board?panels=stat:salud:MEX,chart:educacion:MEX,stat:seguridad:MEX,chart:trabajo-economia:MEX&theme=light&accent=%23004b87&brand=IDB&lang=pt"
  width="100%" height="640" style="border:0" loading="lazy"
  title="Dashboard Futuros — México"></iframe>

Se panels estiver vazio, o board mostra uma dica (?panels=stat:salud:MEX,chart:educacion:BRA) em vez de um frame em branco.

/incrustar — o builder

https://futuros.xyz/incrustar?lang=pt é o builder sem código para os embeds de widget único. Escolha pilar, país, indicador, tipo (stat/chart) e tema; ele mostra uma prévia ao vivo em iframe do valor citado real e entrega um snippet de uma linha para copiar e colar. O dropdown de indicadores é populado com os indicadores reais da célula selecionada, então você só embute uma métrica que existe.

Tematização — semântica de override de themeTokens

Cada widget aplica inline um conjunto completo de variáveis CSS na própria raiz (themeTokens() em _embed-shared.tsx) — não há classe de tema global, então os estilos da página hospedeira não vazam para dentro e o widget não vaza para fora:

TokenPapel?accent= sobrescreve?
--e-bg / --e-panel / --e-lineFundo, cartão, bordaNão
--e-ink / --e-ink-2 / --e-ink-3Hierarquia de textoNão
--e-accentMarca, traço da linha do gráficoSim
--e-goodDelta na direção boaSim — o mesmo hex do acento
--e-badDelta na direção ruim, ressalva de quarentenaNão — permanece vermelho
--e-citeChip de citaçãoNão

O override é deliberadamente parcial: accent substitui exatamente --e-accent e --e-good, nunca --e-bad ou --e-cite. Um parceiro pode aplicar sua marca ao widget e aos deltas positivos; a cor de aviso e o chip de citação não são personalizáveis — você pode fazer white-label do número, não da ressalva.

Garantias de honestidade

O contrato de procedência tem dentes dentro do próprio widget:

  • Nenhum número fabricado. Um embed se recusa a renderizar payloads mock/de fallback — se a fonte de dados da célula não for o corpus estático, ele mostra "Dados não disponíveis" em vez de um valor inventado.
  • A quarentena é visível. Uma célula sinalizada pelos validadores renderiza com uma ressalva explícita de "em revisão" em vez de apresentar silenciosamente um número posto em dúvida.
  • A citação viaja junto. O chip de fonte é reconstruído apenas a partir do citation_id (veja Procedência), então o deep link funciona mesmo que o embed nunca carregue o registro completo de citações.

Framing e segurança

  • As rotas de embed enviam Content-Security-Policy: frame-ancestors * — embutíveis em qualquer página hospedeira.
  • Todas as outras rotas enviam X-Frame-Options: SAMEORIGIN — o app principal não é embutível fora da origem.
  • Embeds são GETs puros de dados estáticos; não há auth e nada a submeter.
  • Os widgets são autocontidos: o tema é aplicado via overrides inline de variáveis CSS na raiz do embed (não uma classe global), então o mesmo número lê corretamente dentro de qualquer página hospedeira.

Os valores por trás de cada embed são as mesmas observações citadas expostas pela API Pública v1 — o embed é apenas uma vista renderizada e linkável de uma célula.

Cada número com sua fonte — a rastreabilidade é o contrato.