✓ Verified 🌐 Web Scrapers ✓ Enhanced Data

Questions Form

Present multiple clarifying questions as an interactive Telegram form using inline buttons.

Rating
4.5 (100 reviews)
Downloads
14,049 downloads
Version
1.0.0

Overview

Present multiple clarifying questions as an interactive Telegram form using inline buttons.

Key Features

1

Compose the Form

2

Send the Header

3

Send Each Question

4

Send the Submit Button

5

Handle Callbacks

6

Use the Answers

Complete Documentation

View Source →

Questions Form

Present multiple clarifying questions as a Telegram inline-button form. All questions appear at once; the user answers in any order, then submits.

When to Use

  • You need 2 or more clarifying questions answered before proceeding
  • Questions have enumerable options (with optional free-text fallback)
  • The channel is Telegram
Do not use this pattern for a single yes/no question — just send one message with buttons for that.

Form Protocol

Step 1: Compose the Form

Define each question internally as an object:

text
{ id: "type",     text: "What type of project?", options: ["Web App", "Mobile", "API"] }
{ id: "timeline", text: "What is your timeline?", options: ["This week", "This month", "No rush"] }
{ id: "budget",   text: "Budget range?",          options: ["< $1k", "$1k-5k", "$5k-10k", "> $10k"] }

Initialize internal tracking state:

text
form_state = { type: null, timeline: null, budget: null }
awaiting_freetext = null
form_submitted = false

Step 2: Send the Header

Send a plain message (no buttons) as the form introduction:

json
{
  "action": "send",
  "channel": "telegram",
  "message": "**I have a few questions before we proceed.**\nPlease answer each one by tapping a button, then tap Submit when done."
}

Step 3: Send Each Question

For each question, send a separate message with inline buttons. Put selectable options in rows of 2-3 buttons. Always put "Other" on its own last row.

The callback_data must follow this convention: form::

Example:

json
{
  "action": "send",
  "channel": "telegram",
  "message": "**1. What type of project is this?**",
  "buttons": [
    [
      { "text": "Web App", "callback_data": "form:type:web" },
      { "text": "Mobile", "callback_data": "form:type:mobile" },
      { "text": "API", "callback_data": "form:type:api" }
    ],
    [
      { "text": "Other (type your answer)", "callback_data": "form:type:other" }
    ]
  ]
}

json
{
  "action": "send",
  "channel": "telegram",
  "message": "**2. What is your timeline?**",
  "buttons": [
    [
      { "text": "This week", "callback_data": "form:timeline:this_week" },
      { "text": "This month", "callback_data": "form:timeline:this_month" },
      { "text": "No rush", "callback_data": "form:timeline:no_rush" }
    ],
    [
      { "text": "Other (type your answer)", "callback_data": "form:timeline:other" }
    ]
  ]
}

json
{
  "action": "send",
  "channel": "telegram",
  "message": "**3. Budget range?**",
  "buttons": [
    [
      { "text": "< $1k", "callback_data": "form:budget:lt_1k" },
      { "text": "$1k-5k", "callback_data": "form:budget:1k_5k" }
    ],
    [
      { "text": "$5k-10k", "callback_data": "form:budget:5k_10k" },
      { "text": "> $10k", "callback_data": "form:budget:gt_10k" }
    ],
    [
      { "text": "Other (type your answer)", "callback_data": "form:budget:other" }
    ]
  ]
}

Step 4: Send the Submit Button

After all questions, send the submit/cancel message:

json
{
  "action": "send",
  "channel": "telegram",
  "message": "**When you've answered all questions above, tap Submit.**",
  "buttons": [
    [{ "text": "\u2713 Submit All Answers", "callback_data": "form:submit" }],
    [{ "text": "\u2717 Cancel", "callback_data": "form:cancel" }]
  ]
}

Step 5: Handle Callbacks

When you receive a callback starting with form::

Regular option (form:: where value is not other):

  • Record the answer: form_state[qid] = value
  • Acknowledge: send "Got it -- : "
"Other" option (form::other):
  • Send: "Type your answer for: "
  • Set awaiting_freetext = qid
  • The next plain text message from the user is their free-text answer
  • Record: form_state[qid] =
  • Acknowledge: "Got it -- : "
  • Clear awaiting_freetext
Submit (form:submit):
  • Check form_state for any null values
  • If incomplete: send "You still need to answer: "
  • If complete: set form_submitted = true and proceed with the collected answers
Cancel (form:cancel):
  • Discard form_state
  • Send: "Form cancelled. Let me know how you'd like to proceed."

Step 6: Use the Answers

Once submitted, reference the collected answers as structured data and proceed:

text
Collected: { type: "mobile", timeline: "End of March", budget: "1k_5k" }

Now continue with the original task using these clarified requirements.

Changing Answers

Users can click a different button for any question at any time before submitting. Simply overwrite the previous value and acknowledge the change:

"Updated -- : "

Callback Data Convention

  • All form callbacks must use the form: prefix
  • Format: form::
  • Keep question IDs short (2-8 chars) — Telegram has a 64-byte callback_data limit
  • Keep values short and use underscores instead of spaces
  • The agent identifies form callbacks by checking if the incoming message starts with form:

Button Layout Rules

  • Maximum 2-3 buttons per row for clean rendering
  • Keep button labels under 20 characters
  • Use Title Case for option labels
  • "Other" button always says: "Other (type your answer)"
  • "Other" button always goes on its own last row
  • Submit button includes checkmark: "\u2713 Submit All Answers"
  • Cancel button includes X mark: "\u2717 Cancel"

Edge Cases and Advanced Patterns

See references/form-patterns.md for:

  • Handling timeouts and abandoned forms
  • Dependent questions (show question B only after A is answered)
  • Large option sets (>6 options)
  • Multi-select questions (toggle pattern)
  • Free-text disambiguation
  • Resuming interrupted forms

Installation

Terminal bash

openclaw install questions-form
    
Copied!

💻Code Examples

form_submitted = false

formsubmitted--false.txt
### Step 2: Send the Header

Send a plain message (no buttons) as the form introduction:

}

.txt
### Step 3: Send Each Question

For each question, send a **separate message** with inline buttons.
Put selectable options in rows of 2-3 buttons. Always put "Other" on its own last row.

The `callback_data` **must** follow this convention: `form:<question_id>:<value>`

Example:

}

.txt
### Step 4: Send the Submit Button

After all questions, send the submit/cancel message:

}

.txt
### Step 5: Handle Callbacks

When you receive a callback starting with `form:`:

**Regular option** (`form:<qid>:<value>` where value is not `other`):
- Record the answer: `form_state[qid] = value`
- Acknowledge: send `"Got it -- <question label>: **<chosen label>**"`

**"Other" option** (`form:<qid>:other`):
- Send: `"Type your answer for: <question text>"`
- Set `awaiting_freetext = qid`
- The **next plain text message** from the user is their free-text answer
- Record: `form_state[qid] = <user's text>`
- Acknowledge: `"Got it -- <question label>: **<user's text>**"`
- Clear `awaiting_freetext`

**Submit** (`form:submit`):
- Check `form_state` for any `null` values
- If incomplete: send `"You still need to answer: <list of unanswered questions>"`
- If complete: set `form_submitted = true` and proceed with the collected answers

**Cancel** (`form:cancel`):
- Discard `form_state`
- Send: `"Form cancelled. Let me know how you'd like to proceed."`

### Step 6: Use the Answers

Once submitted, reference the collected answers as structured data and proceed:
example.txt
{ id: "type",     text: "What type of project?", options: ["Web App", "Mobile", "API"] }
{ id: "timeline", text: "What is your timeline?", options: ["This week", "This month", "No rush"] }
{ id: "budget",   text: "Budget range?",          options: ["< $1k", "$1k-5k", "$5k-10k", "> $10k"] }
example.txt
form_state = { type: null, timeline: null, budget: null }
awaiting_freetext = null
form_submitted = false
example.json
{
  "action": "send",
  "channel": "telegram",
  "message": "**I have a few questions before we proceed.**\nPlease answer each one by tapping a button, then tap Submit when done."
}
example.json
{
  "action": "send",
  "channel": "telegram",
  "message": "**1. What type of project is this?**",
  "buttons": [
    [
      { "text": "Web App", "callback_data": "form:type:web" },
      { "text": "Mobile", "callback_data": "form:type:mobile" },
      { "text": "API", "callback_data": "form:type:api" }
    ],
    [
      { "text": "Other (type your answer)", "callback_data": "form:type:other" }
    ]
  ]
}
example.json
{
  "action": "send",
  "channel": "telegram",
  "message": "**2. What is your timeline?**",
  "buttons": [
    [
      { "text": "This week", "callback_data": "form:timeline:this_week" },
      { "text": "This month", "callback_data": "form:timeline:this_month" },
      { "text": "No rush", "callback_data": "form:timeline:no_rush" }
    ],
    [
      { "text": "Other (type your answer)", "callback_data": "form:timeline:other" }
    ]
  ]
}
example.json
{
  "action": "send",
  "channel": "telegram",
  "message": "**3. Budget range?**",
  "buttons": [
    [
      { "text": "< $1k", "callback_data": "form:budget:lt_1k" },
      { "text": "$1k-5k", "callback_data": "form:budget:1k_5k" }
    ],
    [
      { "text": "$5k-10k", "callback_data": "form:budget:5k_10k" },
      { "text": "> $10k", "callback_data": "form:budget:gt_10k" }
    ],
    [
      { "text": "Other (type your answer)", "callback_data": "form:budget:other" }
    ]
  ]
}

Tags

#browser_and-automation

Quick Info

Category Web Scrapers
Model Claude 3.5
Complexity One-Click
Author edonadei
Last Updated 3/10/2026
🚀
Optimized for
Claude 3.5
🧠

Ready to Install?

Get started with this skill in seconds

openclaw install questions-form