Automate Google Forms submission with Python
Features • Quick Start • Documentation • Examples • Advanced
This is a fork/improved version of the original google form autofill/submit created by tienthanh214, Original Version here
This is a simple and lightweight script to automatically fill and submit Google Forms with random or custom data. The script is highly customizable, allowing you to:
- 🎲 Fill forms with random values
- 📝 Use custom data from JSON files
- 🔄 Submit forms multiple times (batch mode)
- 💾 Save responses for audit trails
- 🧪 Test without submitting (dry-run mode)
It also includes a request body generator for those who prefer manual data input - simply paste a Google Form URL, eliminating the need for manual inspection.
An interactive terminal menu (tui.py) wraps the whole tool — no flags to memorize. The launcher scripts create a local virtual environment, install dependencies, and open the menu on first run.
Windows (PowerShell):
.\run.ps1Windows (cmd / double-click):
run.batAny platform (venv already set up):
python tui.pyFrom the menu you can set the form URL, Preview fields (read-only), do a Dry run to inspect the generated payload, edit settings (email, strategy, count, delay, required-only, progressive, age range), set per-field custom values, and Submit.
forms.gle short links are supported — they're resolved to the full form URL automatically.
Saving settings: menu options 8 (Save settings) / 9 (Load settings) persist your config (URL, email options, strategy, count, custom values, …) to tui_settings.json. Saved settings load automatically the next time you start the TUI.
When a form collects email, you can auto-generate a realistic Indonesian @gmail.com address instead of typing one — a fresh address per submission. Seven styles (eras):
| Style | Who | Examples |
|---|---|---|
classic |
full-name adults | budi.setiawan98, iqbal.ramadhan.handayani, mutami |
professional |
clean, no/little digits | fadil.pangestu, dewi.maulana, hadi.susanti |
millennial |
1985–1999 birth years | ibnu.rahman1987, budi.firmansyah95 |
genz |
aesthetic / gamer / nickname | itsshakira, rafa.luvr, n4ufal.ffx, cherryrara |
alpha |
very aesthetic + leetspeak | 4lvar0777, raih4n.sl33py, xxavi3rx, aqilaaaa |
chinese |
Chinese-Indonesian names | vincentwijaya, ricky.tanoto, melissawibowo1991 |
mix (default) |
weighted blend of all | — |
Extra knobs:
- Gender (
any/male/female) — picks gender-appropriate given names. - Seed — a fixed integer makes the generated sequence reproducible across runs.
- Unique — de-duplicates within a batch/preview.
Names cover regional surnames (Javanese, Batak, etc.), compound names (muhammad…, nur…, Balinese putu/kadek/…), and birth-order prefixes. All output is strictly @gmail.com and obeys Gmail's rules (letters/numbers/dots only, 6–30 chars).
- TUI: Settings → Email settings (toggle, style, gender, seed, unique). Menu Preview sample emails prints a list in any style/gender.
- CLI:
--random-emailplus--email-style {classic,professional,millennial,genz,alpha,chinese,mix},--email-gender {any,male,female},--email-seed N. - Standalone:
python email_generator.py 20 alpha male→ 20 samples (<count> [style] [gender]).
python main.py https://forms.gle/XXXX --random-email --email-style genz --email-gender female --count 5The TUI has a Presets menu that applies a bundle of settings in one tap (URL and custom values are kept) — e.g. Indo Gen Z survey, Gen Alpha (youngest), Professional adults, Bulk realistic mixed, Required only fast, Reproducible (seed 42).
New submission settings (TUI Submission settings, or CLI):
--delay-jitter SEC— random extra delay (0..jitter) per submission, to look less robotic.--timeout SEC— request timeout.--stop-on-failure— abort a batch on the first failed submission.
Some forms ask age as a multiple-choice / dropdown with range options (e.g. <18, 18–25, 26–35, 36–45, >45) rather than a text box. With an age range set, the tool now picks the option(s) overlapping your range instead of choosing randomly:
age 18-25→ ticks18–25age 26-45→ randomly among26–35and36–45
It understands <, >, ≤, ≥, +, and hyphen/en-dash/em-dash separators. Same age_range also fills age text boxes. Toggle with TUI Fill settings → Match age range to choices, or CLI --no-age-match to disable.
Checkbox questions (the "pilih lebih dari satu" / select-multiple type) are fully supported — multiple choices are submitted as repeated form keys, exactly as Google Forms expects. By default the random strategy ticks 1–3 boxes per field; you can control this:
- TUI: Fill settings → Checkbox min/max selections.
- CLI:
--checkbox-min Nand--checkbox-max N.
Counts are clamped to the number of available options (e.g. asking for 4–6 on a 3-option field ticks all 3). The fixed strategy ticks the first checkbox-min options.
Manual setup, if you'd rather not use the launcher:
python -m venv .venv .venv\Scripts\python -m pip install -r requirements.txt # Windows .venv/bin/python -m pip install -r requirements.txt # macOS/LinuxOn this machine the
pythoncommand resolves through thepylauncher (Python 3.14, uv-managed); usepyin place ofpythonifpythonisn't on PATH.
|
|
# Python 3.7 or higher
python --version
# Install dependencies
pip install -r requirements.txt
# Or install directly
pip install requestsRequirements:
- Python 3.7+
requestslibrary (≥2.31.0)
pip install -r requirements.txtpython form.py 'https://docs.google.com/forms/d/e/YOUR_FORM_ID/viewform' -o autopython main.py 'https://docs.google.com/forms/d/e/YOUR_FORM_ID/viewform'That's it! 🎉 Your form has been submitted with random data.
If you only want to fill and submit a Google Form with random data, skip to the AutoFill and Submit section.
Below are the detailed steps to understand and customize the process.
The URL of the Google Form will look like this:
https://docs.google.com/forms/d/e/form-index/viewform
Just copy it and replace viewform with formResponse:
https://docs.google.com/forms/d/e/form-index/formResponse
Just copy the Google Form URL and run the form.py script. It will return a dictionary containing the name attributes of each input element and the data you need to fill out.
python form.py <your-gg-form-url>| Mode | Command | Description |
|---|---|---|
| Console | python form.py <url> |
Print to console (default) |
| Auto-generate | python form.py <url> -o auto |
Save to form_outputs/ with auto-generated name |
| Folder | python form.py <url> -o my_forms/ |
Save to specified folder with auto-generated name |
| File | python form.py <url> -o path/to/file.txt |
Save to specific file path |
# Save to auto-generated file
python form.py 'https://docs.google.com/forms/d/e/1FAIpQLSc.../viewform' -o auto
# Save to specific file
python form.py 'https://docs.google.com/forms/d/e/1FAIpQLSc.../viewform' -o results.txt
# Only required fields with verbose output
python form.py 'https://docs.google.com/forms/d/e/1FAIpQLSc.../viewform' -o auto -r --verbosepython form.py -hClick to expand manual method
Open the Google Form, then open DevTools (inspect) to inspect the input elements.
Each input element you need to fill has a format: name = "entry.id"
Try filling each input box to discover its ID.
Important:
- If the form requires email, add the
emailAddressfield- For multiple-page forms, add the
pageHistoryfield with comma-separated page numbers (starting from 0)
- Example: 4-page form →
"pageHistory": "0,1,2,3"
Create a dictionary where keys are the name attributes of each input element, and values are the data you need to fill out:
# Example
def fill_form():
name = get_name_by_day()
date, hour = str(get_gmt_time()).split(' ')
date = date.split('-')
hour = hour.split(':')
if (int(hour[0]) < 10):
hour[0] = hour[0][1:]
value = {
# Text
"entry.2112281434": name,
# Dropdown menu
"entry.1600556346": "Sài Gòn",
# Date
"entry.77071893_year": date[0],
"entry.77071893_month": date[1],
"entry.77071893_day": date[2],
# Hour
"entry.855769839": hour[0] + 'h',
# Checkbox
"entry.819260047": ["Cafe", "Fences"],
# One choice
"entry.1682233942": "Okay"
}
print(value, flush=True)
return valueUse POST method with requests:
def submit(url, data):
try:
requests.post(url, data=data)
print("Submitted successfully!")
except:
print("Error!")
submit(url, fill_form())Done! ✨
Run the main.py script with the Google Form URL to automatically fill and submit with random data:
python main.py <your-gg-form-url># 🎲 Basic submission with random values
python main.py 'https://docs.google.com/forms/d/e/1FAIpQLSc.../viewform'
# ⚡ Only fill required fields
python main.py 'https://docs.google.com/forms/d/e/1FAIpQLSc.../viewform' -r
# 📧 Custom email address
python main.py 'https://docs.google.com/forms/d/e/1FAIpQLSc.../viewform' --email myemail@gmail.com
# 🎂 Specify age range for age fields
python main.py 'https://docs.google.com/forms/d/e/1FAIpQLSc.../viewform' --age-range "18-25"
# 🧪 Dry run (preview without submitting)
python main.py 'https://docs.google.com/forms/d/e/1FAIpQLSc.../viewform' --dry-runChoose how to populate form fields:
| Strategy | Description | Usage |
|---|---|---|
| Random (default) | Fills fields with random realistic values | python main.py <url> |
| Fixed | Uses consistent values across submissions | python main.py <url> --strategy fixed |
Examples:
# Random values (default)
python main.py <form_url>
# Fixed values
python main.py <form_url> --strategy fixedSubmit the same form multiple times with automatic delays:
# Submit 10 times with 2-second delay
python main.py <form_url> --count 10 --delay 2
# Rapid submissions (be careful!)
python main.py <form_url> --count 5 --delay 0.5Batch submission includes:
- ⏱️ Automatic delays between submissions
- 📊 Success/failure tracking
- 📈 Detailed statistics summary
- 🔄 Progress indicators
Example output:
==================================================
SUBMISSION SUMMARY
==================================================
Total attempts: 10
Successful: 10 ✓
Failed: 0 ✗
Success rate: 100.0%
==================================================
NEW! For multi-page forms, simulate clicking the "Next" button on each page:
# Automatically detect and submit multi-page forms progressively
python main.py <form_url> --progressiveWhat is Progressive Mode?
- 🔄 Submits each page separately (like clicking "Next")
- ⏱️ Adds realistic delays between pages
- ✅ Better mimics human behavior
- 🎯 Useful for forms with page-specific validation
Examples:
# Single progressive submission
python main.py <form_url> --progressive
# Batch progressive submissions
python main.py <form_url> --progressive --count 5 --delay 2
# Progressive with custom data
python main.py <form_url> --progressive --custom-file data.json -vHow it works:
- Detects number of pages in the form
- Submits data for page 1 → receives response
- Updates pageHistory to "0,1"
- Submits data for page 2 → receives response
- Continues until final page
- Shows progress for each page
Output example:
Multi-page form detected with 3 pages
Submitting progressively (simulating 'Next' button clicks)...
📄 Submitting page 1/3...
✓ Page 1/3 submitted (Next)
📄 Submitting page 2/3...
✓ Page 2/3 submitted (Next)
📄 Submitting page 3/3...
✓ Page 3/3 submitted (Final page)
✓ All pages submitted successfully!
💡 Tip: Use verbose mode (
-v) to see detailed page-by-page progress
Automatically fill age/umur fields with values from a specified range:
# Fill age fields with ages between 18-25
python main.py <form_url> --age-range "18-25"
# Different age ranges
python main.py <form_url> --age-range "20-30"
python main.py <form_url> --age-range "30-50"How it works:
- 🔍 Smart detection: Automatically identifies age fields by keywords:
- English:
age - Indonesian:
umur,usia,tahun - Spanish:
edad - German:
alter
- English:
- 🎲 Random generation: Generates random ages within your specified range
- ✅ Works with both strategies: Compatible with random and fixed fill strategies
- 🌍 Multi-language support: Detects age fields in multiple languages
Examples:
# Submit form with ages between 18-20
python main.py <form_url> --age-range "18-20"
# Batch submissions with age range
python main.py <form_url> --age-range "25-35" --count 10
# Combine with other options
python main.py <form_url> --age-range "20-30" --progressive --save-responsesValidation:
- ✅ Age range format:
"min-max"(e.g.,"18-25") - ✅ Valid range: 0-150 years
- ✅ Min must be less than max
- ❌ Invalid formats will show helpful error messages
Override specific fields with custom values using a JSON file:
Step-by-step:
# 1. Generate form template to get entry IDs
python form.py <form_url> -o auto
# 2. Create custom_values.json{
"entry.123456": "My custom answer",
"entry.789012": ["Option A", "Option B"],
"emailAddress": "myemail@gmail.com"
}# 3. Use it
python main.py <form_url> --custom-file custom_values.json💡 Tip: See custom_values_example.json for a complete example.
Preview what will be submitted without actually submitting:
python main.py <form_url> --dry-runPerfect for:
- ✅ Testing your fill strategy
- ✅ Validating custom values
- ✅ Debugging form data
- ✅ Previewing batch submissions
- ✅ Checking multi-page form structure
Example output with multi-page form:
=== DRY RUN MODE - No actual submission ===
Generated form data:
{
"entry.123456": "Test value",
"entry.789012": "Another value",
"pageHistory": "0,1,2"
}
ℹ️ This is a multi-page form with 3 pages
pageHistory field: 0,1,2
Save generated form data to JSON files for record-keeping:
# Save single submission
python main.py <form_url> --save-responses
# Save all batch submissions
python main.py <form_url> --count 10 --save-responses📁 Files are saved to
form_outputs/with timestamps for easy tracking.
Control output verbosity:
# 📢 Verbose mode (shows all details including debug info)
python main.py <form_url> -v
# 🔇 Quiet mode (errors only)
python main.py <form_url> -q
# 📝 Normal mode (default - info and errors)
python main.py <form_url>Verbose mode shows:
- Page-by-page submission progress
- Detailed form data
- Network requests
- All debug information
python main.py https://docs.google.com/forms/d/e/ABC123/viewform# Submit 20 times with random values, 1.5s delay, save all responses
python main.py https://docs.google.com/forms/d/e/ABC123/viewform \
--count 20 \
--delay 1.5 \
--save-responses# 1. Generate form template
python form.py https://docs.google.com/forms/d/e/ABC123/viewform -o auto
# 2. Edit the generated file to create your custom_data.json
# 3. Submit with custom data
python main.py https://docs.google.com/forms/d/e/ABC123/viewform \
--custom-file custom_data.json \
--email realuser@example.com# Dry run to check data generation with verbose output
python main.py https://docs.google.com/forms/d/e/ABC123/viewform \
--dry-run \
--verbose# Submit multi-page form with progressive mode (simulates clicking "Next")
python main.py https://docs.google.com/forms/d/e/MULTIPAGE_FORM/viewform \
--progressive \
--verboseWhat happens:
- Automatically detects 3-page form
- Submits page 1, waits, submits page 2, waits, submits page 3
- Shows progress for each page
# Submit multi-page form 10 times progressively
python main.py https://docs.google.com/forms/d/e/MULTIPAGE_FORM/viewform \
--progressive \
--count 10 \
--delay 2 \
--save-responses \
--verbose# Submit form with specific age range
python main.py https://docs.google.com/forms/d/e/ABC123/viewform \
--age-range "18-25" \
--count 10 \
--save-responses# Fill and submit only required fields with fixed values
python main.py https://docs.google.com/forms/d/e/ABC123/viewform \
--required \
--strategy fixed \
--count 5 \
--delay 2 \
--save-responsesClick to expand/collapse
url Google Form URL
-r, --required Only fill required fields
--email EMAIL Email address for email fields (default: test@example.com)
--strategy {random,fixed}
Fill strategy: random or fixed values
--custom-file FILE JSON file with custom field values
--age-range MIN-MAX Age range for age/umur fields (e.g., "18-25", "20-30")
--count N Number of times to submit (default: 1)
--delay SEC Delay between submissions in seconds (default: 1.0)
--dry-run Generate data but do not submit
--count N Number of times to submit (default: 1)
--delay SEC Delay between submissions in seconds (default: 1.0)
--dry-run Generate data but do not submit
--progressive Use progressive page-by-page submission for multi-page forms
--save-responses Save generated responses to JSON
-v, --verbose Enable verbose logging
-q, --quiet Minimal output (errors only)
Click to expand/collapse
url Google Form URL
-o, --output PATH Output: 'console', 'auto', folder path, or file path
-r, --required Only include required fields
-c, --no-comment Don't include explanatory comments
-v, --verbose Enable verbose logging
The main.py script is a powerful tool that can be customized in several ways:
For advanced users, create custom fill strategies:
from main import FillStrategy
import form
class CustomFillStrategy(FillStrategy):
def fill(self, type_id, entry_id, options, required=False, entry_name=''):
# Your custom logic here
if "name" in entry_name.lower():
return "John Doe"
if type_id == form.FIELD_TYPE_DATE:
return "2025-12-31"
# Fall back to parent class for other fields
return super().fill(type_id, entry_id, options, required, entry_name)
# Use in code:
from main import main
strategy = CustomFillStrategy(email="custom@example.com")
main(url, fill_strategy=strategy)from main import generate_request_body, submit_form, RandomFillStrategy
# Generate data
url = "https://docs.google.com/forms/d/e/ABC123/viewform"
strategy = RandomFillStrategy(email="test@example.com")
data = generate_request_body(url, fill_strategy=strategy)
# Customize specific fields
data["entry.123456"] = "My custom value"
# Submit
success = submit_form(url, data)
print("Success!" if success else "Failed!")| # | Tip | Description |
|---|---|---|
| 1️⃣ | Use dry-run first | Always test with --dry-run before actual submissions |
| 2️⃣ | Respect rate limits | Use appropriate delays (1-2 seconds recommended) for batch submissions |
| 3️⃣ | Save responses | Use --save-responses for audit trails and debugging |
| 4️⃣ | Custom values | Great for production-like test data |
| 5️⃣ | Verbose mode | Use -v when debugging issues |
| 6️⃣ | Start small | Test with --count 1 before large batch submissions |
| 7️⃣ | Check saved files | Files in form_outputs/ include timestamps for easy tracking |
| 8️⃣ | Progressive for multi-page | Use --progressive for forms with multiple pages to simulate real user flow |
| 9️⃣ | Auto-detection | Multi-page forms are automatically detected - progressive mode is optional |
| 🔟 | Age range for surveys | Use --age-range for demographic surveys to ensure realistic age distributions |
- Auto vs Progressive: Tool automatically includes
pageHistoryfield. Use--progressivefor page-by-page submission - Testing multi-page: Use
--dry-runto see thepageHistoryfield value - Debugging: Use
-vwith--progressiveto see each page being submitted - Page delays: Progressive mode adds 0.5s delay between pages by default
- Batch testing: Combine
--progressive --count Nfor realistic batch testing of multi-page forms
The enhanced version includes comprehensive error handling for:
- 🌐 Network timeouts and connection errors
- 🔗 Invalid URLs or malformed responses
- 💾 File I/O errors
- 📄 JSON parsing errors
⚠️ Missing required fields- 🔒 SSL certificate issues
All errors are logged with clear messages and the program exits with appropriate status codes for scripting.
Use -h or --help to get comprehensive help for each script:
python main.py -h
python form.py -hThe tool fully supports progressive page-by-page submission for multi-page Google Forms, simulating the behavior of clicking the "Next" button on each page.
- Submits all form data at once
- Includes
pageHistoryfield automatically - Single HTTP request
- ⚡ Fast and efficient
python main.py <form_url>- Submits data page-by-page
- Simulates clicking "Next" button
- Multiple HTTP requests (one per page)
- 🎭 More realistic user behavior
python main.py <form_url> --progressiveStandard Mode Flow:
1. Generate all form data
2. Add pageHistory: "0,1,2,3"
3. Submit → Done ✓
Progressive Mode Flow:
1. Detect 4 pages in form
2. Submit page 1 data (pageHistory: "0")
3. Wait 0.5s ⏱️
4. Submit page 2 data (pageHistory: "0,1")
5. Wait 0.5s ⏱️
6. Submit page 3 data (pageHistory: "0,1,2")
7. Wait 0.5s ⏱️
8. Submit page 4 data (pageHistory: "0,1,2,3")
9. Done ✓
✅ Use Progressive Mode When:
- Form has page-specific validation
- You want to mimic real user behavior
- Testing form's multi-page logic
- Debugging page navigation issues
- Form requires client-side page progression
✅ Standard Mode is Fine When:
- Simple batch testing
- Fast automated submissions
- Form accepts all data at once
- You don't need page-by-page simulation
| Feature | Standard Mode | Progressive Mode |
|---|---|---|
| Speed | ⚡ Fast | 🐢 Slower (0.5s per page) |
| Requests | 1 request | N requests (N = pages) |
| Realism | Medium | High |
| Debugging | Simple | Detailed per-page |
| Use Case | Bulk testing | Realistic simulation |
| Auto-detection | ✅ Yes | ✅ Yes |
Both modes automatically detect multi-page forms by:
- Parsing form structure from
FB_PUBLIC_LOAD_DATA_ - Counting page breaks (
FORM_SESSION_TYPE_ID) - Automatically adding
pageHistoryfield
- Single page: No
pageHistoryfield - 2 pages:
"0,1" - 3 pages:
"0,1,2" - 4 pages:
"0,1,2,3" - And so on...
python main.py https://docs.google.com/forms/d/e/FORM_ID/viewform --progressiveOutput:
🔄 Multi-page form detected (3 pages) - Progressive mode enabled
Submitting progressively (simulating 'Next' button clicks)...
📄 Submitting page 1/3...
✓ Page 1/3 submitted (Next)
📄 Submitting page 2/3...
✓ Page 2/3 submitted (Next)
📄 Submitting page 3/3...
✓ Page 3/3 submitted (Final page)
✓ All pages submitted successfully!
python main.py https://docs.google.com/forms/d/e/FORM_ID/viewform \
--progressive \
--count 5 \
--delay 3 \
--save-responses \
--verboseWhat this does:
- Submits the multi-page form 5 times
- Uses progressive mode (page-by-page)
- 3 second delay between complete submissions
- Saves all responses to JSON files
- Shows detailed verbose output
# Test with standard mode
python main.py <url> --dry-run -v
# Test with progressive mode
python main.py <url> --progressive --dry-run -vThis lets you see the difference in how data is prepared and submitted.
- Page delay: 0.5 seconds between pages
- Request timeout: 10 seconds per request
- SSL verification: Enabled
from main import submit_form_progressive
# Custom page delay
success = submit_form_progressive(
url=form_url,
data=form_data,
page_delay=1.0, # 1 second between pages
timeout=15 # 15 second timeout
)| Issue | Solution |
|---|---|
| "Single page form detected" | Form is actually single page - progressive mode not needed |
| Progressive mode too slow | Expected (0.5s delay per page). Use standard mode for speed |
| Page submission failed | Check verbose output with -v, verify pageHistory, try standard mode |
| Wrong page count | Use --dry-run -v to see detected structure |
| Form not submitting | Try without --progressive first, check if form requires login |
from main import (
main,
submit_form_progressive,
generate_request_body,
RandomFillStrategy,
get_page_count
)
# Check if form is multi-page
url = "https://docs.google.com/forms/d/e/YOUR_FORM/viewform"
page_count = get_page_count(url)
print(f"Form has {page_count} pages")
# Generate data
strategy = RandomFillStrategy(email="test@example.com")
data = generate_request_body(url, fill_strategy=strategy)
# Submit progressively
if page_count > 1:
success = submit_form_progressive(url, data, page_delay=1.0)
else:
success = submit_form(url, data)- Test with dry-run first:
--dry-run -vto see form structure and pageHistory - Use verbose for debugging:
-vshows detailed page-by-page submission - Standard mode for speed: Unless you specifically need progressive behavior
- Save responses for analysis:
--save-responseshelps track what was submitted - Combine with custom data: Progressive mode works seamlessly with
--custom-file - Start with small counts: Test with
--count 1before batch submissions - Monitor rate limits: Use appropriate delays to avoid overwhelming the form
- ✅ Page-by-page submission - Each page submitted separately
- ✅ Automatic detection - No manual configuration needed
- ✅ Realistic simulation - Mimics actual user clicking "Next"
- ✅ Detailed progress - See each page being processed
- ✅ Compatible - Works with all existing features
- ✅ Flexible - Optional - standard mode still available
Please note that this script currently operates only with Google Forms that do not require user authentication.