NeetoForm CLI

Work with your forms and submissions from your terminal, your scripts, and your coding agent. Open source, and it runs on macOS, Linux and Windows.

Install the NeetoForm CLI

macOS with Homebrew:

brew install neetozone/tap/neetoform

macOS or Linux:

curl -fsSL https://neetoform.com/cli/install.sh | sh

Windows (PowerShell):

irm https://neetoform.com/cli/install.ps1 | iex

Next, sign in to NeetoForm. This opens your browser, so there's no API key to copy or manage:

neetoform login --subdomain your-workspace

To let your AI coding assistant use the NeetoForm CLI, run the appropriate setup command from your project folder:

neetoform setup claude      # Claude Code
neetoform setup cursor      # Cursor
neetoform setup codex       # Codex
neetoform setup copilot     # GitHub Copilot
neetoform setup gemini      # Antigravity CLI and Gemini CLI
neetoform setup windsurf    # Devin (formerly Windsurf)

Every command supports --json for structured output and --toon for a more compact format that uses fewer tokens when processed by AI assistants. See the NeetoForm CLI reference for the complete list of commands.

Automate with the CLI

Why use a CLI when MCP already exists? Because some tasks don't need AI at all. You can run them on a schedule using the NeetoForm CLI and tools you already use, such as jq, curl, and your cloud CLI. No AI account, no model costs, and consistent results every time.

Share submission counts every morning

Save the following script as ~/form-counts.sh and make it executable:

#!/bin/sh
neetoform forms list --status active --page-size 100 --json \
  | jq '{text: ([.data[] | "\(.title): \(.submissions_count)"]
      | join("\n"))}' \
  | curl -s -X POST -H "Content-Type: application/json" \
      -d @- "$SLACK_WEBHOOK_URL"

Add it to your crontab to run every weekday at 9 AM:

0 9 * * 1-5 ~/form-counts.sh

Export form submissions to CSV

Find the form by its title, then export all submissions to a CSV file, with a separate column for each question.

form_id=$(neetoform forms list --search "Contact sales" --json \
  | jq -r '.data[] | select(.title == "Contact sales") | .id')
questions=$(neetoform forms show "$form_id" --json \
  | jq -c '.data.questions')

echo "$questions" \
  | jq -r '["Submitted at"] + map(.label) | @csv' > contact-sales.csv
page=1
while :; do
  out=$(neetoform forms submissions list "$form_id" \
    --page "$page" --page-size 100 --json) || exit 1
  echo "$out" | jq -r --argjson q "$questions" '.data[]
    | (.responses | map({(.slug): .value}) | add // {}) as $answers
    | [.created_at] + [$q[].slug | $answers[.] // "" | tostring] | @csv'
  total=$(echo "$out" | jq '.pagination.total_pages')
  [ "$total" -le "$page" ] && break
  page=$((page + 1))
done >> contact-sales.csv

Send new leads to your CRM

Every 15 minutes, send new submissions to your CRM, skipping those that have already been processed.

form_id=$(neetoform forms list --search "Contact sales" --json \
  | jq -r '.data[] | select(.title == "Contact sales") | .id')
touch seen.txt
page=1
while :; do
  out=$(neetoform forms submissions list "$form_id" --order desc \
    --page "$page" --page-size 100 --json) || exit 1
  echo "$out" | jq -c '.data[]' | while read -r submission; do
    id=$(echo "$submission" | jq -r '.id')
    grep -qx "$id" seen.txt && continue
    # Mark it sent only if the CRM accepted it, so a failed send retries
    curl -fsS -X POST -H "Content-Type: application/json" \
      -d "$submission" https://crm.example.com/api/leads \
      && echo "$id" >> seen.txt
  done
  total=$(echo "$out" | jq '.pagination.total_pages')
  [ "$total" -le "$page" ] && break
  page=$((page + 1))
done

Back up all form submissions nightly

form_page=1
while :; do
  forms=$(neetoform forms list --page "$form_page" \
    --page-size 100 --json) || exit 1
  echo "$forms" | jq -r '.data[].id' | while read -r form_id; do
    page=1
    while :; do
      out=$(neetoform forms submissions list "$form_id" \
        --page "$page" --page-size 100 --json) || exit 1
      echo "$out" | jq -c --arg form "$form_id" \
        '.data[] | {form: $form} + .'
      total=$(echo "$out" | jq '.pagination.total_pages')
      [ "$total" -le "$page" ] && break
      page=$((page + 1))
    done
  done
  form_total=$(echo "$forms" | jq '.pagination.total_pages')
  [ "$form_total" -le "$form_page" ] && break
  form_page=$((form_page + 1))
done > submissions.jsonl

aws s3 cp submissions.jsonl \
  "s3://your-backup-bucket/neetoform/$(date +%F).jsonl"

Notice when a form goes quiet

Every evening, compare today's submission counts with yesterday's and flag forms that didn't move.

neetoform forms list --status active --page-size 100 --json \
  | jq '[.data[] | {id, title, submissions_count}]' > counts-today.json

[ -s counts-yesterday.json ] && jq -r \
  --slurpfile y counts-yesterday.json '
  ($y[0] | map({(.id): .submissions_count}) | add) as $prev
  | .[] | select($prev[.id] == .submissions_count)
  | "No new submissions: \(.title)"' counts-today.json

mv counts-today.json counts-yesterday.json

Add and remove people from your HR scripts

# Onboarding
neetoform team-members create \
  --emails oliver@example.com,sam@example.com --role Standard

# Offboarding: deactivates the member and keeps their forms
# and submissions
member_id=$(neetoform team-members list --email sam@example.com \
  --quiet | jq -r '.[0].id')
neetoform team-members delete "$member_id"

Let a coding agent build it for you

You don't have to write these scripts yourself. Claude Code, Codex, or another coding agent can write the automation and use the open-source NeetoForm CLI to work with your account. Run neetoform setup claude (or setup codex, setup cursor) once, then ask:

Every Monday at 8 AM, use the NeetoForm CLI to export last week's Lifeline Run registration submissions to CSV and email it to the race team. Write the script, test it, and set up the cron job.

Using the NeetoForm CLI, write a script that saves every submission from all our active forms as JSON, one file per form.

You get the convenience of a chat, and the result is a script you can read, run, and commit.

Terminal recording of Claude Code. It explores the neetoform CLI, writes a script that exports last week's Lifeline Run registrations to CSV and emails them to the race team, tests it, and adds a cron job that runs at 8 AM every Monday.
Claude Code builds the Monday export with the NeetoForm CLI, tests it, and schedules it with cron.

When to use the CLI and when to use MCP

Both read the same forms and submissions. Pick based on how the work reaches NeetoForm.

Use MCP when:

  • You want to understand the answers. Summaries, themes, scores, and comparisons need someone to read the responses.
  • You're asking a question. "Which forms got nothing this week?" needs someone to look and explain.
  • You don't know a form's exact name. Describe the form in your own words, and the assistant finds it and reads its questions for you.
  • You don't use a terminal. NeetoForm hosts the server. There's nothing to install.

Use the CLI when:

  • No AI should be in the loop. A cron job or CI step runs the CLI with nothing but the binary. No model account, no cost per run.
  • The output feeds another program. The CLI prints raw JSON for jq, a spreadsheet, your CRM, or your own script.
  • You're working through thousands of submissions. The CLI pages through everything unattended.
  • The run has to be repeatable. A command records exactly what ran and does the same thing every time.

You can also have both. With neetoform setup claude, your AI assistant drives the CLI for you, so a plain-language request still ends in a command you can read and reuse.

Open source

The NeetoForm CLI is open source and available on GitHub. You can inspect its code, see exactly what it sends to NeetoForm, and customize it for your workflows. Written in Go, it runs on macOS, Linux, and Windows.

The NeetoForm CLI is built on neeto-cli-commons, the shared foundation for all Neeto CLI tools. This means the commands and conventions you learn in one Neeto CLI will feel familiar across the others.

Found a bug or have an idea for a new command? Open an issue or submit a pull request on GitHub.

Frequently asked questions

Can I automate NeetoForm without using AI?

Yes. The NeetoForm CLI works directly from your terminal, shell scripts, cron jobs, and CI workflows. You don't need Claude, ChatGPT, or any other AI service to automate tasks.

Is the NeetoForm CLI open source?

Yes. The NeetoForm CLI is open source and available on GitHub. You can inspect the code, modify it, and contribute improvements.

Gotowy, aby stworzyć swój następny formularz?

Zacznijmy.