Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.tako.com/llms.txt

Use this file to discover all available pages before exploring further.

Zero Data Retention lets you render charts without persisting your data on Tako servers. You send the visualization payload at render time, and data exists only in the request and the user’s browser.

How it works

  1. Generate a card via Tako’s Visualize API and receive a card_id and visualization_data object.
  2. Render the card using one of two embed modes:
    • Form POST — sends data via a hidden form submission to an iframe. Simple, works everywhere.
    • postMessage — sends data via window.postMessage(). Supports updating the chart without reloading the iframe.
  3. Data is not stored by Tako; it exists only in your request and the user’s browser.

Form POST

The form POST approach submits visualization_data as a hidden form field targeting an iframe. The iframe loads, renders the chart, and the data is never persisted.

Using the widget

<script src="tako-zdr-embed.js"></script>
<div id="my-zdr-chart"></div>

<script>
  window.TakoZDREmbed.render({
    containerId: "my-zdr-chart",
    takoUrl: "https://tako.com",
    cardId: "YOUR_CARD_ID",
    visualizationData: {
      viz_config: { /* chart config */ },
      data: { /* chart data */ }
    },
    width: "100%",
    height: "600px"
  });
</script>

Without the widget

Use a hidden form that targets an iframe:
function loadTakoEmbed(iframeId, cardId, visualizationData) {
  const iframe = document.getElementById(iframeId);
  const form = document.createElement('form');
  form.method = 'POST';
  form.action = `https://tako.com/embed/${cardId}/`;
  form.target = iframe.name;
  form.style.display = 'none';

  const input = document.createElement('input');
  input.type = 'hidden';
  input.name = 'visualization_data';
  input.value = JSON.stringify(visualizationData);
  form.appendChild(input);

  document.body.appendChild(form);
  form.submit();
  document.body.removeChild(form);
}

postMessage

The postMessage approach loads an empty iframe shell, then sends data via window.postMessage(). This is more efficient for dynamic use cases because you can update the chart data without reloading the iframe.
postMessage mode requires the card to be created with postmessage_embed: true in the ThinViz create request.

Message protocol

The iframe and parent page communicate via structured messages:
DirectionMessage typeDescription
Iframe → Parenttako::readyIframe shell is loaded and ready to receive data
Parent → Iframetako::vizdataParent sends visualization data to render
Iframe → Parenttako::vizdata::receivedChart rendered successfully
Iframe → Parenttako::vizdata::errorError processing the visualization data

Flow

Parent Page                        Iframe
    │                                 │
    │── 1. Create iframe (GET) ──────>│  Loads empty shell
    │                                 │
    │<── 2. tako::ready ─────────────│  Ready to receive data
    │                                 │
    │── 3. tako::vizdata ────────────>│  Send visualization_data
    │                                 │
    │<── 4. tako::vizdata::received ──│  Chart rendered
    │                                 │
    │── 5. tako::vizdata (update) ───>│  Update without reload
    │                                 │

Using the widget

Set embedMode: 'postmessage' to use postMessage mode. The widget handles the entire handshake automatically.
<script src="tako-zdr-embed.js"></script>
<div id="my-chart"></div>

<script>
  var handle = window.TakoZDREmbed.render({
    containerId: "my-chart",
    takoUrl: "https://tako.com",
    cardId: "YOUR_CARD_ID",
    visualizationData: {
      viz_config: { /* chart config */ },
      data: { /* chart data */ }
    },
    embedMode: "postmessage",
    width: "100%",
    height: "600px",
    onLoad: function () { console.log("Chart ready"); },
    onError: function (err) { console.error("Error:", err); }
  });

  // Update the chart with new data (no iframe reload):
  handle.update({ viz_config: { /* ... */ }, data: { /* ... */ } });

  // Clean up when done:
  handle.destroy();
</script>

Without the widget

Implement the handshake yourself:
// 1. Create iframe pointing to the embed shell
const iframe = document.createElement('iframe');
iframe.src = `https://tako.com/embed/${cardId}/`;
iframe.style.width = '100%';
iframe.style.height = '600px';
iframe.style.border = 'none';
document.getElementById('container').appendChild(iframe);

// 2. Listen for messages from the iframe
window.addEventListener('message', function (event) {
  if (event.source !== iframe.contentWindow) return;

  if (event.data.type === 'tako::ready') {
    // 3. Iframe is ready — send the visualization data
    iframe.contentWindow.postMessage({
      type: 'tako::vizdata',
      visualizationData: {
        viz_config: { /* chart config */ },
        data: { /* chart data */ }
      }
    }, '*');
  }

  if (event.data.type === 'tako::vizdata::received') {
    console.log('Chart rendered successfully');
  }

  if (event.data.type === 'tako::vizdata::error') {
    console.error('Render error:', event.data.error);
  }
});
To update the chart later, send another tako::vizdata message — no need to reload the iframe.

Which mode to use

Form POSTpostMessage
SetupSimpler — no handshake neededRequires message listener
UpdatesReloads iframe each timeUpdates in-place, no reload
Card requirementAny ZDR cardRequires postmessage_embed: true
Best forStatic embeds, one-time rendersDashboards, real-time data, interactive apps

End-to-end flow

  1. Call POST /v1/beta/visualize with your data and query.
  2. Extract card_id and visualization_data from the response.
  3. Render with either the form POST or postMessage approach shown above.