Sprucely title background

Integración

Puedes integrar dashboards interactivos de Sprucely.io en tu propio sitio web o aplicación web de tres formas: incrustándolos con un iframe HTML estándar, renderizándolos de forma nativa con el runtime independiente de JavaScript, o montando los componentes independientes de React. El iframe es la forma más rápida de configurar; los runtimes independientes dibujan los dashboards directamente en tu página y te permiten insertar nuevos datos en tiempo real. La estructura JSON que leen los runtimes independientes - dashboards, gráficos y datasets - está documentada en la referencia de formato de datos. Para automatización de dashboards impulsada por IA, consulta la sección de MCP APIs.

Incrustación de dashboards en HTML

La integración más sencilla utiliza el elemento HTML estándar iframe y funciona en cualquier sitio web, o incluso en páginas HTML locales. El dashboard debe estar compartido, ya sea en el Cloud o en On-premise, para que se cargue correctamente. Ten en cuenta que los dashboards On-premise solo se cargarán cuando el cliente que accede a ellos esté dentro de la misma red corporativa.

Instrucciones:

1) Extrae el enlace de incrustación del dashboard - En la página Dashboards, asegúrate de que tu dashboard esté compartido y luego haz clic en el icono de este dashboard. Un banner emergente verde te notificará que el enlace se copió al portapapeles. Lo usarás para reemplazar el contenido de src del iframe HTML a continuación.

2) Incrusta el dashboard con un tamaño fijo

<html>
  <head>
    <title>Sprucely.io Dashboard</title>
  </head>
  <body>
    <h1>Sprucely.io Dashboard</h1>
    <iframe src="https://www.sprucely.io/service/dashboards/embed/[userId]/[dashboardId]/"
            allow="clipboard-write"
            style="height: 500px; width: 700px;"
            title="Sprucely.io Dashboard"></iframe>
  </body>
</html>

(o) Incrusta el dashboard con ancho dinámico - Redimensiona automáticamente el dashboard según el ancho del documento padre

Puedes usar el parámetro de estilo aspect-ratio para recalcular automáticamente la altura en función del ancho.

<html>
  <head>
    <title>Sprucely.io Dashboard</title>
  </head>
  <body>
    <h1>Sprucely.io Dashboard</h1>
    <iframe src="https://www.sprucely.io/service/dashboards/embed/[userId]/[dashboardId]/"
            allow="clipboard-write"
            scrolling="no"
            style="width: 100%; aspect-ratio: 1.5; border: none;"
            title="Sprucely.io Dashboard"></iframe>
  </body>
</html>

3) Otras opciones útiles de incrustación

Puedes añadir modificaciones de estilo personalizadas al bloque style del elemento iframe, para personalizar la apariencia del marco. Estos parámetros siguen las directrices de HTML y CSS estándar. El siguiente ejemplo añade un borde gris alrededor del dashboard:

<html>
  <head>
    <title>Sprucely.io Dashboard</title>
  </head>
  <body>
    <h1>Sprucely.io Dashboard</h1>
    <iframe src="https://www.sprucely.io/service/dashboards/embed/[userId]/[dashboardId]/"
            allow="clipboard-write"
            style="height: 100%; width: 100%; border: 2px solid grey;"
            title="Sprucely.io Dashboard"></iframe>
  </body>
</html>

Incrustación con JavaScript independiente

El runtime independiente renderiza los dashboards directamente dentro de tu página - sin iframe. Tus datos se cargan en una base de datos en el navegador y se dibujan como gráficos totalmente interactivos; el runtime solo contacta con Sprucely.io para validar tu token de acceso.

Instrucciones:

1) Crea un token de acceso - En la sección Tokens de acceso de tu perfil, crea un token de acceso para el origen desde el que se sirven tus páginas (por ejemplo https://www.yourdomain.com). El runtime valida que el origen de la página de incrustación coincida con el token antes de renderizar.

2) Carga el runtime y renderiza un dashboard - Añade el script del runtime a tu página, conecta la base de datos en el navegador una vez con sprucely_db, y luego renderiza cada dashboard con sprucely_create. La página completa a continuación también conecta un botón que añade más filas:

<html>
  <head>
    <title>Orders Dashboard</title>
  </head>
  <body>
    <div id="database"></div>
    <div id="orders_dashboard"></div>
    <button onclick="addRows()">Add rows</button>

    <script src="https://www.sprucely.io/cross-origin/sprucely-runtime.min.js"></script>
    <script>
      const data = {
        name:    "Orders",
        headers: ["region", "amount", "items"],
        types:   ["VARCHAR", "FLOAT", "INTEGER"],
        entries: [
          ["North", 120.50, 2],
          ["South",  89.95, 1],
          ["North", 432.00, 5],
          ["South",  74.50, 1]
        ]
      };

      const dashboard = {
        config: {
          type: "dashboard",
          style: {
            widget: {
              color: "#667FFF",
              backgroundColor: "#0C0B29",
              primaryColor: "#01EEAE",
              primaryColorSubtle: "#C70584",
              secondaryColor: "#2C2B49"
            }
          }
        },
        data: {
          type: "dash",
          children: [
            {
              type: "dash_stacker_hor",
              children: [
                { type: "dash_chart", datasetId: "Orders", x: "region", chartType: "bar", dataFunction: "count" },
                { type: "dash_chart", datasetId: "Orders", x: "amount", y: "items", chartType: "hexbin", dataFunction: "count" }
              ]
            }
          ]
        }
      };

      sprucely_db({
        id: "database",
        host: "https://www.yourdomain.com",
        accessToken: "YOUR_ACCESS_TOKEN"
      });
      sprucely_create({ id: "orders_dashboard", dashboard, data });

      function addRows() {
        sprucely_add({
          name:    "Orders",
          headers: ["region", "amount", "items"],
          types:   ["VARCHAR", "FLOAT", "INTEGER"],
          entries: [
            ["East", 310.40, 3],
            ["West", 129.95, 1]
          ]
        });
      }
    </script>
  </body>
</html>

3) Añade datos en tiempo real - Llama a sprucely_add con filas adicionales en cualquier momento. Cada dashboard que utiliza el dataset se actualiza automáticamente:

sprucely_add({
  name:    "Orders",
  headers: ["region", "amount", "items"],
  types:   ["VARCHAR", "FLOAT", "INTEGER"],
  entries: [
    ["East", 310.40, 3],
    ["West", 129.95, 1]
  ]
});

Referencia de funciones

  • sprucely_db({ id, host, accessToken }) - conecta la base de datos en el navegador y valida tu token de acceso contra el origen de la página. Renderiza un banner de estado en el elemento identificado por id. Llámala una vez por página, antes de crear dashboards.
  • sprucely_create({ id, dashboard, data }) - renderiza un dashboard en el elemento identificado por id. El parámetro dashboard define el layout y el estilo; data proporciona el dataset con su nombre, encabezados, tipos de columna (VARCHAR, INTEGER, FLOAT o TIMESTAMP) y filas - consulta la referencia de formato de datos.
  • sprucely_add(data) - añade filas al dataset cuyo nombre coincide con un dataset ya cargado, y luego actualiza todos los dashboards que lo utilizan.

Incrustación con React independiente

Si tu sitio está construido con React, puedes renderizar dashboards como componentes en lugar de cargar el script manualmente. Los componentes utilizan los mismos tokens de acceso, definiciones de dashboard y formato de dataset que el runtime independiente de JavaScript.

Instrucciones:

1) Crea un token de acceso - Igual que con JavaScript independiente, crea un token de acceso para el origen de tu sitio en la sección Tokens de acceso de tu perfil.

2) Renderiza los componentes del dashboard - Obtén el runtime desde https://www.sprucely.io/cross-origin/sprucely-runtime.min.cjs.js y colócalo en tu proyecto. Monta un componente Sprucely.Database por página, y un componente Sprucely.Dashboard por dashboard. Los dashboards muestran un indicador de carga hasta que la base de datos valida el token de acceso, y luego se renderizan. La aplicación completa a continuación renderiza dos dashboards a partir de datasets independientes y añade nuevas filas al primero después de cinco segundos:

// Get https://www.sprucely.io/cross-origin/sprucely-runtime.min.cjs.js
// and place it in your project, next to this file.

import React, { useEffect } from "react";
import { createRoot } from "react-dom/client";
import Sprucely, { sprucely_add } from "./sprucely-runtime.min.cjs.js";

const style = {
  widget: {
    color: "#667FFF",
    backgroundColor: "#0C0B29",
    primaryColor: "#01EEAE",
    primaryColorSubtle: "#C70584",
    secondaryColor: "#2C2B49"
  }
};

const orders = {
  name:    "Orders",
  headers: ["region", "amount", "items"],
  types:   ["VARCHAR", "FLOAT", "INTEGER"],
  entries: [
    ["North", 120.50, 2],
    ["South",  89.95, 1],
    ["North", 432.00, 5],
    ["South",  74.50, 1]
  ]
};

const returns = {
  name:    "Returns",
  headers: ["reason", "amount", "days"],
  types:   ["VARCHAR", "FLOAT", "INTEGER"],
  entries: [
    ["Damaged", 45.00, 3],
    ["Late",    12.50, 8],
    ["Changed", 99.90, 2]
  ]
};

const moreOrders = {
  name:    "Orders",
  headers: ["region", "amount", "items"],
  types:   ["VARCHAR", "FLOAT", "INTEGER"],
  entries: [
    ["East", 310.40, 3],
    ["West", 129.95, 1]
  ]
};

const ordersDashboard = {
  config: { type: "dashboard", style },
  data: {
    type: "dash",
    children: [
      {
        type: "dash_stacker_hor",
        children: [
          { type: "dash_chart", datasetId: "Orders", x: "region", chartType: "bar", dataFunction: "count" },
          { type: "dash_chart", datasetId: "Orders", x: "amount", y: "items", chartType: "hexbin", dataFunction: "count" }
        ]
      }
    ]
  }
};

const returnsDashboard = {
  config: { type: "dashboard", style },
  data: {
    type: "dash",
    children: [
      {
        type: "dash_stacker_hor",
        children: [
          { type: "dash_chart", datasetId: "Returns", x: "amount", y: "days", d: "amount", r: "days", chartType: "dot", dataFunction: "average" }
        ]
      }
    ]
  }
};

const App = () => {
  useEffect(() => {
    const timer = setTimeout(() => { sprucely_add(moreOrders); }, 5000);
    return () => clearTimeout(timer);
  }, []);

  return (
    <>
      <Sprucely.Database host="https://www.yourdomain.com" accessToken="YOUR_ACCESS_TOKEN" />
      <Sprucely.Dashboard id="orders_dashboard" dashboard={ordersDashboard} data={orders} />
      <Sprucely.Dashboard id="returns_dashboard" dashboard={returnsDashboard} data={returns} />
    </>
  );
};

createRoot(document.getElementById("root")).render(<App />);

Servir claves de corta duración

El token de acceso que creas arriba es de larga duración y está pensado para permanecer como un secreto del lado del servidor. Si tu propio backend sirve las páginas de incrustación - en lugar de una página sin backend propio - no necesitas incluir ese token de larga duración en la página en absoluto - tu backend puede intercambiarlo, de servidor a servidor, por un token de renderizado de corta duración (15 minutos) justo antes de servir cada página, y solo el token de renderizado llega al navegador. Un token de renderizado que un visitante extrae de la página solo es útil durante minutos, no de forma indefinida.

Instrucciones:

1) Intercambia tu token de acceso por un token de renderizado - desde tu backend, llama a POST https://www.sprucely.io/api/auth/render_token con tu token de acceso como credencial bearer. La respuesta incluye el nuevo token, su host vinculado y su tiempo de vida en segundos:

// On your server, immediately before serving each embedding page:
const response = await fetch("https://www.sprucely.io/api/auth/render_token", {
  method:  "POST",
  headers: { Authorization: "Bearer " + process.env.SPRUCELY_ACCESS_TOKEN }
});
const { token, expires_in } = await response.json(); // expires_in: 900 (15 minutes)

// Send only the render token to the browser - never the long-lived access
// token itself:
res.send(`
  <script src="https://www.sprucely.io/cross-origin/sprucely-runtime.min.js"></script>
  <script>
    sprucely_db({
      id: "database",
      host: "https://www.yourdomain.com",
      accessToken: "${token}"
    });
  </script>
`);

2) Sirve el token de renderizado al navegador - úsalo exactamente igual que un token de acceso al llamar a sprucely_db o al montar Sprucely.Database. Repite el intercambio antes de servir cada página (o mediante un temporizador si almacenas en caché la página renderizada), de modo que el navegador nunca reciba un token válido por más de 15 minutos.

Referencia de funciones

  • POST /api/auth/render_token - intercambia un token de acceso válido, enviado como Authorization: Bearer <token>, por un token de renderizado. Devuelve { token, host, expires_in } con expires_in fijado en 900 segundos. Un token de renderizado no puede intercambiarse por otro token de renderizado - solo un token de acceso de larga duración puede solicitar uno.

Configuración de seguridad

Si tu sitio aplica una Política de Seguridad de Contenido (CSP), las integraciones independientes de JavaScript y React anteriores necesitan que se permitan algunas fuentes antes de que los dashboards se carguen - el runtime carga su script desde Sprucely.io, abre una base de datos en el navegador respaldada por WebAssembly, y valida tu token de acceso contra nuestra API, y cada una de ellas requiere un permiso CSP explícito. Si tu sitio no utiliza CSP, puedes omitir esta sección.

Añade las siguientes fuentes a tu política existente - son directivas para fusionar, no una política completa que reemplace la que ya tienes:

script-src   'self' https://www.sprucely.io 'wasm-unsafe-eval';
connect-src  'self' https://www.sprucely.io;
worker-src   'self' blob: https://www.sprucely.io;

Para qué sirve cada directiva:

  • script-src - https://www.sprucely.io carga el script del runtime. 'wasm-unsafe-eval' es necesario para compilar y ejecutar la base de datos en el navegador, que está construida sobre WebAssembly.
  • connect-src - se contacta con https://www.sprucely.io para validar tu token de acceso y cargar los archivos WebAssembly y worker de la base de datos.
  • worker-src - la base de datos en el navegador ejecuta sus consultas en un hilo en segundo plano, creado a partir de una URL blob:.

Ninguna de las anteriores requiere 'unsafe-inline' - el runtime de Sprucely en sí nunca lo necesita. Si mantienes tus propias definiciones de dashboard y dataset en una etiqueta <script> inline, como en el ejemplo de JavaScript independiente anterior, o tu propia página utiliza estilos inline, añade 'unsafe-inline' a script-src o style-src o considera usar nonces de CSP.