Export Typeform to monday.com: Native Integration, Zapier, or the API
← All posts
GuideOct 27, 2026· 8 min read

Export Typeform to monday.com: Native Integration, Zapier, or the API

To export Typeform to monday.com, start with monday’s own Typeform integration: open the board, click Integrate, pick a Typeform recipe, connect both accounts, and map each question to a column. From then on every new submission becomes an item. That covers most teams. You need something else in three cases: you want to move responses that already exist, your form uses question types the integration does not carry, or some of the “responses” are scans and PDFs that never touched Typeform. This guide walks through each route and where it stops working.

If you are after raw response data rather than a board, the Export Typeform to JSON guide covers the Responses API and CSV exports in detail. This post is about getting answers into monday.com items.

Route 1: the native monday.com Typeform integration

monday.com documents the setup in its Typeform integration article. The flow is short:

  1. Open the board that should receive responses and click Integrate in the top right.
  2. Search the Automation center for Typeform and choose a recipe, for example one that creates an item when a form is submitted.
  3. Connect your monday.com account to your Typeform account.
  4. Pick the form and map each Typeform question to a board column.

monday adds an integration column to the board automatically to keep the link between the two apps. Typeform also has a guide for connecting an existing form to a board, and a separate monday.com app view that generates a new typeform from inside the board. Typeform notes that monday.com is a partner-supported integration, so support questions go to monday.

What the native integration will not do

Read the limits before you rely on it:

  • Some question types do not map. monday’s page lists Logic Jumps, Multiple Choice, Statement, Question Group, Hidden fields, Video, Payment, and Ranking as unsupported, and a note on the same page also names Phone, Dropdown, and Picture. The lists are not fully consistent, so build a test form with your real question types and submit it once before going live.
  • Partial submissions are not updated. If you use Typeform partial submissions, monday gets the first version only. A later edit by the respondent does not change the item.
  • It is forward-looking. The recipe fires on new submissions. Responses collected before you connected the board are not imported.

If any of those is a deal breaker, move to one of the routes below.

Route 2: Zapier or another automation tool

Typeform lists Zapier templates for monday.com, such as creating a monday.com group when someone completes a typeform. An automation tool is worth it when you need steps in between: look up an existing item before creating a duplicate, split one submission into several items, or format a multiple choice answer into a text column that the native recipe will not fill.

The trade-off is another account, another place where the mapping lives, and task-based pricing on the automation side. It also still only reacts to new submissions unless you build a separate backfill.

Route 3: Typeform webhook plus the monday.com API

When you want full control over mapping, deduplication, and backfill, write the glue yourself. It is less code than it sounds.

Typeform sends each submission to your URL through webhooks. Each answer carries the question ref and a value keyed by type (text, email, date, choice, and so on). monday.com accepts items through one GraphQL endpoint, https://api.monday.com/v2, with the create_item mutation. The items reference shows that column_values is a JSON string keyed by column ID, and the column values guide explains which column types take simple strings and which need objects.

A minimal mapping step in Python:

import json
import os
import requests

MONDAY_TOKEN = os.environ["MONDAY_TOKEN"]
BOARD_ID = "1234567890"

# Typeform question ref -> monday.com column id
COLUMN_MAP = {
    "company": "text_company",
    "work_email": "email_contact",
    "start_date": "date_start",
    "plan": "status_plan",
}

def answer_value(answer):
    kind = answer["type"]
    if kind == "choice":
        return answer["choice"].get("label")
    if kind == "choices":
        return ", ".join(answer["choices"].get("labels", []))
    return answer.get(kind)

def to_column_values(form_response):
    values = {}
    for answer in form_response["answers"]:
        column_id = COLUMN_MAP.get(answer["field"]["ref"])
        if not column_id:
            continue
        value = answer_value(answer)
        if column_id.startswith("email_"):
            values[column_id] = {"email": value, "text": value}
        elif column_id.startswith("date_"):
            values[column_id] = {"date": value}
        elif column_id.startswith("status_"):
            values[column_id] = {"label": value}
        else:
            values[column_id] = value
    return values

def create_item(item_name, column_values):
    query = """
    mutation ($board: ID!, $name: String!, $values: JSON!) {
      create_item(board_id: $board, item_name: $name,
                  column_values: $values, create_labels_if_missing: true) { id }
    }"""
    variables = {
        "board": BOARD_ID,
        "name": item_name,
        "values": json.dumps(column_values),
    }
    r = requests.post(
        "https://api.monday.com/v2",
        json={"query": query, "variables": variables},
        headers={"Authorization": MONDAY_TOKEN},
        timeout=30,
    )
    r.raise_for_status()
    body = r.json()
    if body.get("errors"):
        raise RuntimeError(body["errors"])
    return body["data"]["create_item"]["id"]

Four details that save debugging time:

  • Stringify only column_values. The variable itself must be a JSON string, but the rest of the request body is normal JSON. Do not run the whole variables object through json.dumps a second time.
  • Use column IDs, not titles. “Work email” on the board might be email_mkx3a9 under the hood. Query the board’s columns once and store the IDs.
  • Match the column type. Email columns want email and text keys, as the email column reference shows. Date columns want {"date": "YYYY-MM-DD"}. Status columns accept a label, and create_labels_if_missing adds a new label instead of failing (it needs permission to change the board structure).
  • Verify the webhook. Set a secret on the Typeform webhook and check the signature before you write anything to the board.

Backfilling responses you already have

The same mapping handles history. Pull past submissions with Typeform’s Responses API, page through them, and pass each one to create_item. Store the Typeform response_id in a text column so a rerun can skip items it already created. This is the step the native integration and most Zapier templates do not give you.

When the form never reached Typeform

Plenty of intake still arrives on paper or as PDFs: a printed copy of the survey filled in at an event, a partner who sent back a scanned form, a screenshot forwarded by email. There is no Typeform response_id for those, so no recipe will see them. If they need to land on the same board, read the page into the same field shape and reuse create_item.

With OCRskill you declare the keys you want and get JSON back:

curl "https://api.ocrskill.com/ocr.json?fields=last_name,first_name,email,company_name?" \
  -H "Authorization: Bearer sk-your-key-here" \
  -F "file=@signup-form-scan.jpg"

Required fields fail with a 400 when the page cannot support them, so an unreadable scan does not create a half-empty item. Optional keys end in ?. Map the returned keys to your monday column IDs the same way COLUMN_MAP does for Typeform refs, and tag those items with a source column so reviewers know they came from a scan. The form data extraction API post covers form OCR in more depth, and the OCR JSON API reference lists the supported field names.

Which route to pick

Situation Route
New submissions, simple question types Native monday.com integration
Extra steps, lookups, or reformatting Zapier or a similar automation tool
Unsupported question types, deduplication, or history Webhook plus create_item, with a Responses API backfill
Paper, PDF, or screenshot forms OCR to JSON, then the same create_item call

Conclusion

The native integration is the right default, but it only moves new, fully supported submissions and it never revisits partial ones. Before you commit to it, submit a test response with every question type you use and check the board. If anything is missing, the webhook route is a few dozen lines of code, gives you a backfill for free through the Responses API, and lets scanned forms join the same board once OCR turns them into the same keys. Keep the Typeform response_id or a scan filename on every item, and reruns stay safe.