Using Freeform and Structured Data Inputs
This feature is in beta. Contact your Technical Account Manager for access.
Freeform and Structured Data are two input formats that let the person generating a presentation supply a whole chunk of content, by uploading a file or pasting it in, instead of picking from a list or typing a single value.
They differ in what Matik does with that content. A Freeform input is a block of text, inserted exactly as supplied. A Structured Data input is a table, built from an uploaded CSV or JSON file.
Both are useful whenever the data you want in a presentation doesn't live in a connected data source. The content travels with the generation itself: someone hands Matik a block of text or a table of rows at generation time, and Matik feeds it into your Dynamic Content. For background on inputs in general, see the Inputs Overview.
Choosing Between Freeform and Structured Data
| Freeform | Structured Data | |
|---|---|---|
| What the user supplies | A .txt file, or pasted text |
A .csv or .json file, or pasted content |
| What Matik does with it | Inserts it as a single block of text | Turns it into a table of rows and columns |
| What you configure | Nothing beyond an optional default | A Content Format (CSV or JSON), and the columns |
| Best for | Prose you want a model to read: transcripts, notes, reports, briefs | Numbers and records you want on the slide as a table, or analyzed row by row |
Note: A Structured Data input set to JSON behaves like a Freeform input until you define its columns. With no columns, the whole object is inserted as text rather than becoming a table. See Working with Freeform or Structured Data Inputs.
When to Use These Inputs
Both formats shine when the content is produced somewhere outside Matik and changes with every generation. The most common pattern is powering a template with output from an AI tool.
- Generate from your own AI agent through Matik's MCP. Teams that run Claude, ChatGPT, or a custom agent can connect it to Matik's MCP server and kick off Matik generations from inside their agent. The agent produces the content, whether a written summary, a table of numbers, or a structured object, and passes it straight into the input as it starts the generation. No copying between tools.
- Paste or upload AI output directly in Matik. If you'd rather work in Matik, generate the content in your AI tool, then paste or upload it into the input on the generation form.
- Bring in one-off data that isn't in a warehouse. A spreadsheet a colleague sent you, a JSON payload from an internal tool, a paragraph someone wrote: anything you'd otherwise have to load into a data source first.
Creating the Input
Create one the same way you create any input: from the Inputs page, from the Dynamic Content editor by typing &: followed by a name, or from the input side panel. In the Input Format selector, choose Freeform or Structured Data.
Configuring a Freeform input
There is nothing to configure. A Freeform input is always plain text, so the only field specific to it is Default Value (Optional), covered below.
Configuring a Structured Data input
A Structured Data input has a Content Format of either CSV or JSON. New inputs start on CSV. What you configure next depends on which one you pick.
- CSV, with Columns (Optional): Name the columns to pull from the uploaded file, in order. Matik matches your names against the file's header row, ignoring case and surrounding spaces, then keeps only those columns and puts them in the order you listed. Leave this empty and Matik uses the file's own header row as-is.
- JSON, with JSON → Table Columns: Define each column you want and the jq expression that fills it. This is what turns the object into a table. Leave it empty and the object is inserted as text instead.
Both formats also offer Default Value (Optional), a file or block of content Matik falls back on when the person generating supplies nothing. This is worth setting for boilerplate content that rarely changes, since it lets people generate without uploading anything.
Note: Switching the Content Format clears any columns you declared and any default file you uploaded. A column declaration is written against one format, since a jq expression means nothing to a CSV file and a header name means nothing to a JSON object. Set the format first, then declare your columns.
Filling In the Input at Generation Time
When someone generates a presentation that uses either input, the field on the form offers two tabs:
-
Upload File: Choose a file from their computer. The file picker filters to the matching extension:
.txtfor Freeform, and.csvor.jsonfor Structured Data, depending on the Content Format. - Paste Content: Paste the content straight into a text box. This is handy for content that's already on the clipboard, like output an AI tool just produced.
Either way, the content is what gets fed into your Dynamic Content. If you set a default, the field arrives pre-filled and the person can generate without supplying anything.
Working with Freeform or Structured Data Inputs
You reference either input the way you reference any other: type &: followed by the input's name wherever the content should go. What matters is where you reference it.
Send these inputs to an Insights Dynamic Content or a Static Dynamic Content. Those are the two places we know both formats work in full:
- Insights Dynamic Content. The content becomes part of the prompt. A Freeform input is inserted as text. A Structured Data input is rendered as a Markdown table, so the model reads it as structured data. Narrative and Snowflake Cortex Dynamic Content work the same way.
-
Static Text or Static Table Dynamic Content. The content becomes that Dynamic Content's own result, which you then tag onto a slide. A Structured Data input becomes the table itself, as long as the body is nothing but
&:input_name.
If you reference one of these inputs somewhere Matik cannot use it, Matik blocks the save where it can and reports it at generation otherwise. See Troubleshooting.
Freeform
Matik treats a Freeform input as a single raw string and inserts it exactly as supplied. That makes it the natural fit for a prompt: you hand the model a block of raw material and let it do the analysis. For example, in an Insights Dynamic Content prompt:
Read the following sales call transcript and list the three most important follow-up actions for the account team, with a one-line rationale for each: &:call_transcript
Whatever text the person pastes or uploads for the call_transcript input replaces &:call_transcript before the prompt runs.
Structured Data from a CSV
Matik parses the CSV into rows and treats the first row as the header. Those header names become the column names, and every following row becomes a data row: the same table shape a SQL query or API call would return. For example, if someone supplies this CSV:
account_name,arr,region,owner Acme Corp,120000,West,J. Rivera Globex,85000,East,S. Okafor Initech,45000,Central,M. Lang
Matik reads it as a four-column table with three rows. Tag &:account_data into an Insights prompt and Matik renders it as a Markdown table for the model. Put it on its own as the body of a Static Table Dynamic Content and those rows become the content's result.
Declaring Columns on the input narrows and reorders that table. If you declare account_name and arr, Matik keeps only those two columns, in that order, and drops region and owner. This is useful when the file people upload is an export with more columns than your slide needs.
Note: Declared columns are a convenience, not a contract. If a name you declared isn't in the uploaded file, Matik uses the file's own columns instead and warns you, rather than failing the generation. Always include a header row in the file, or your first row of real data is mistaken for one and dropped.
Structured Data from JSON
Choose JSON when the content is a structured object, the kind of output an AI agent or an internal API returns. To turn that object into a table, use the JSON → Table Columns section. You define the columns you want, and for each one you write a jq expression that pulls the values out of the object. (jq is a standard query language for JSON, the same syntax you may have used on the command line.)
Say the person supplies this JSON:
{
"summary": { "overall_score": 68, "tier": "Growth" },
"signals": [
{ "name": "New Records Created", "value": 210, "trend": "up", "score": 2 },
{ "name": "Reports Run", "value": 540, "trend": "flat", "score": 1 },
{ "name": "Contacts Added", "value": 18, "trend": "down", "score": 0 }
]
}
To turn the signals array into a table, you'd define four columns:
| Column Name | jq Expression |
|---|---|
signal |
.signals[].name |
value |
.signals[].value |
trend |
.signals[].trend |
score |
.signals[].score |
Matik runs each expression against the object and lines the results up row by row, producing a four-column table with one row per signal. From there it behaves exactly like the CSV table above.
jq handles nested fields and arrays, so you can reach into deeply structured objects: .metrics.quarterly.revenue pulls a nested value, and .line_items[].sku pulls one value per element of an array. Give each column the exact jq expression that isolates the value you want.
If you define no columns at all, Matik passes the whole object through as raw text. That is the right choice for a prompt where you want the model to read the entire structure rather than specific numbers.
Referencing individual columns
You don't reference CSV headers or JSON keys directly in a template. To get at individual values, declare the columns on the input, then create a Static Text or Static Table Dynamic Content whose body is nothing but &:input_name. Matik gives that content the input's declared columns as its sub-content fields, so you can tag each one with dot notation: {{dynamic_content_name.column_name}}.
The body has to be the bare input reference. Adding any prose around it makes Matik treat the whole thing as text instead. Column names are case-sensitive and cannot contain spaces to be tagged this way, and sub-content expects a single row. See Sub-Content.
Examples
These examples show common ways teams use these inputs to power a template with content produced outside Matik.
Example 1: Turn a call transcript into recommendations (Freeform)
You have an account-review template with an Insights Dynamic Content that generates recommended next steps. You set up a Freeform input named call_transcript and reference it in the Insights prompt with &:call_transcript, like the prompt shown in Freeform.
After a customer call, you paste the transcript or a raw customer report into the Paste Content tab of the call_transcript input. Matik feeds it to the Insights prompt, which reads the whole conversation and writes the follow-up actions straight onto the slide. The source material is different every time and lives nowhere in your data warehouse, which is exactly what these inputs are for.
Example 2: Put an uploaded account list on the slide (Structured Data, CSV)
You maintain a territory review template with a table of the rep's top accounts. The list comes out of a CRM export that nobody has connected to Matik, and it has fifteen columns when the slide has room for three.
You create a Structured Data input named account_data with the Content Format set to CSV, and declare three Columns: account_name, arr, renewal_date. Then you create a Static Table Dynamic Content whose entire body is &:account_data, and tag it onto the slide as a table.
At generation, the rep uploads the export on the Upload File tab. Matik keeps the three columns you declared, in the order you declared them, drops the other twelve, and renders the table on the slide. The rep never has to clean up the file first.
Tip: Because columns are matched by header name rather than by position, the export can change its column order or gain new columns without breaking your slide. Only a rename of one of your three declared headers matters.
Example 3: Feed a JSON record into Insights for analysis (Structured Data, JSON, no columns)
Your team runs an AI tool that outputs a structured account health scorecard as JSON: an overall score, a set of usage signals with their recent values and trends, and a few flags. You want a slide that reads the whole picture and writes a short analysis of where adoption is slipping and what the account team should do about it.
You set up a Structured Data input named health_scorecard with the Content Format set to JSON and no columns defined, so the whole object passes through as raw text. You reference it in an Insights Dynamic Content prompt:
You are reviewing a customer's product-adoption scorecard, provided as JSON. Summarize the account's health in four sentences, call out the two signals most at risk, and recommend a next step for the account team. &:health_scorecard
This is the right choice when you want the model to reason over the entire structure holistically, rather than pull out specific numbers. Because the agent that produced the scorecard can also connect to Matik's MCP, this whole flow can run without leaving the agent: it generates the JSON and kicks off the Matik generation, passing the object in as the value for health_scorecard.
Example 4: Map JSON to a table so you can tag exact metrics (Structured Data, JSON, with columns)
Same scorecard JSON, but now you want the signals to land in a fixed table on the slide, identically on every generation. Defining columns makes the data predictable, so downstream Dynamic Content always sees the same shape.
On a Structured Data input named scorecard with the Content Format set to JSON, you map the signals array into the four columns shown in Structured Data from JSON: signal, value, trend, and score. Every generation now produces the same four-column table, in the same order, whatever else the AI tool's raw JSON contains.
From there you have two ways to get it onto the slide:
-
As a table. Create a Static Table Dynamic Content whose body is
&:scorecardand tag it onto the slide. The four columns render as the table. -
As individual metrics. Because the input declares its columns, that same Static Dynamic Content exposes them as sub-content fields. Tag a single value inline with dot notation, so a headline can read
Top signal: {{scorecard.signal}}. Sub-content expects a single row, so use this when your jq expressions isolate one record rather than a list.
The payoff is repeatability: because the columns are pinned down, each tagged value shows up in the exact spot every time, no matter what the AI tool's raw JSON looks like around it. As with the other examples, an agent can supply the JSON and start the generation through Matik's MCP, or someone can paste or upload it on the form.
Best Practices
- Always include a header row in CSV: The first row supplies your column names. Without it, your first data row is treated as the header and dropped from the data.
- Test your jq expressions before you rely on them: Write and check each column's jq expression against a real sample of the JSON you expect, so the columns line up the way you intend.
- Use Freeform for prompts, Structured Data for tables: If you want a model to read prose or a whole object, Freeform (or JSON with no columns) is the simpler choice. Define columns when you need the values in fixed positions on the slide.
- Declare CSV columns when people upload exports: Naming the columns you want protects your slide from a file that carries extra columns or reorders them.
- Set the Content Format before you declare columns: Switching between CSV and JSON clears both your columns and your default file.
- Set a default for boilerplate content: If the content is usually the same, set it as the default so people can generate without pasting or uploading each time.
Limitations
- Supported Dynamic Content only: Reference these inputs from an Insights Dynamic Content or a Static Text or Static Table Dynamic Content. Those are the places they are supported today.
-
Column tagging needs a bare reference: Sub-content fields are only available on a Static Dynamic Content whose body is nothing but
&:input_name. Any surrounding prose and Matik treats the whole body as text. -
No field-by-field referencing in a query: You reference the whole value with
&:input_name. For JSON, you shape it into columns up front with jq expressions rather than referencing individual keys inline.
Troubleshooting
| Message | What it means | What to do |
|---|---|---|
| File input "name" is only supported for Google Sheets, Excel, REST, and prompt-based data sources. | The input is referenced from a data source that can't accept one, most often a SQL query. | Remove the reference, or move it to an Insights or Static Dynamic Content. |
| File input "name" produces tabular data, which isn't supported for this data source. | A Structured Data input resolves to a table, and it was referenced somewhere that accepts only text. | Reference it from an Insights or Static Dynamic Content, or switch the input to Freeform. |
| Column 'name' requires a jq expression when blob_format is json | A column on a JSON input was saved without the expression that fills it. | Fill in the jq expression, or remove the empty column row. |
Comments
0 comments
Article is closed for comments.