A form submission that needs internal follow-up is only useful if someone actually acts on it, and that requires turning a raw response into a task with an owner and a deadline rather than leaving it buried in a responses tab.
This script listens for form submissions and appends a row to a dedicated Tasks sheet containing a description built from the submission, a calculated due date, an assigned owner based on simple routing rules, and a status of Open.
Keeping this as a plain sheet-based queue, rather than reaching for the Tasks Advanced Service, means the whole thing works immediately without extra API enablement steps and stays easy for a non-technical teammate to review and update.
The due date logic and owner routing shown here are simple starting points you can extend once you see how form data flows into structured queue rows.
Need this built? Hire a Google Apps Script developer →
Sheet / project setup
| Tasks sheet column | Letter | Source |
|---|---|---|
| Description | A | Form Details |
| Owner | B | Routed from Topic |
| DueDate | C | Today + turnaround days |
| Status | D | Open |
| Source | E | Form response URL |
What It Does
On each form submission, the script builds a short task description from the respondent's name and request details, looks up an owner based on the submitted request type, calculates a due date a fixed number of days out, and appends the resulting row to the Tasks sheet with a status of Open.
Because owner routing is driven by a small lookup object rather than hardcoded conditionals, adding a new request type and owner later just means adding one new entry to that object.
Prerequisites
Create a Tasks sheet with the columns Description, Owner, DueDate, Status, and Source before running the script, since appendRow writes values positionally and expects that exact column order.
Decide on your owner-routing rules ahead of time, mapping each possible value of the form's request-type question to the name or email of the person who should handle that kind of task.
Walkthrough
Paste the createTaskFromForm function into the script editor, fill in the OWNER_ROUTES object with your request types and owners, and set DEFAULT_DUE_DAYS to your team's normal turnaround time.
Add an installable On form submit trigger for this function, separate from any sheet-processing or confirmation-email triggers already configured on the same form.
Submit a test response for each request type in your routing table and confirm the Tasks sheet gets one row per submission with the correct owner and a due date the expected number of days ahead.
Edge Cases
A submission with a request type that is not present in OWNER_ROUTES still creates a task row, but the Owner column is filled with a configurable Unassigned fallback so nothing is silently dropped from the queue.
Due dates calculated to land on a weekend are left as-is in this version rather than being shifted to the next business day, which is worth adjusting if your team does not work weekends.
Testing
Submit test responses for two different request types mapped to two different owners and confirm both rows land in the Tasks sheet with the correct owner assigned to each.
Submit a response with a request type deliberately missing from OWNER_ROUTES and confirm the resulting row still appears with the Unassigned fallback rather than causing the trigger to fail.
Hardening
Add a duplicate-submission guard using the form response's own timestamp and respondent email so accidentally submitting the same form twice in quick succession does not create two identical open tasks.
Wrap the whole function body in try/catch and log failures to a dedicated error sheet, since a broken trigger on a task-creation form could otherwise cause real requests to vanish without anyone noticing.
Variations
Once your team is comfortable with the sheet-based queue, migrate the same routing and due-date logic onto the Tasks Advanced Service after enabling it in the Services panel, which lets tasks show up directly in each owner's Google Tasks list.
Add a status-change trigger elsewhere in your workflow that emails the requester automatically when their task's Status column changes from Open to Done.
createTaskFromForm.gs
createTaskFromForm turns a submission into a queue row by looking up an owner from a routing object and computing a due date a fixed number of days out.
// Queue a follow-up task row from a form submission
function createTaskFromForm(e) {
var TASKS_SHEET_NAME = 'Tasks';
var DEFAULT_DUE_DAYS = 3;
var OWNER_ROUTES = {
'Billing': 'finance-team@example.com',
'Technical': 'support-team@example.com',
'General': 'ops-team@example.com'
};
var namedValues = e.namedValues;
var name = namedValues['Full Name'] ? namedValues['Full Name'][0] : 'Unknown';
var requestType = namedValues['Request Type'] ? namedValues['Request Type'][0] : 'General';
var details = namedValues['Details'] ? namedValues['Details'][0] : '';
var owner = OWNER_ROUTES[requestType] || 'Unassigned';
var dueDate = new Date();
dueDate.setDate(dueDate.getDate() + DEFAULT_DUE_DAYS);
var description = requestType + ' request from ' + name + ': ' + details;
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(TASKS_SHEET_NAME);
sheet.appendRow([description, owner, dueDate, 'Open', 'Form Submission']);
}- Line 5: Keeping the routing rules as a plain object means adding a new request type and owner later is a one-line change rather than a new conditional branch.
- Line 16: Falling back to Unassigned when a request type has no matching route ensures every submission still produces a task instead of one silently vanishing.
- Line 18: Adding DEFAULT_DUE_DAYS to today's date computes a concrete deadline the moment the task is created, rather than leaving the due date blank.
- Line 20: Building a single description string from the request type, name, and details gives whoever works the queue enough context without opening the original form response.
- Line 23: appendRow writes the status as Open explicitly, which is the value later automations or teammates check for when deciding a task still needs attention.
Deploy this example
- 01
Open Apps Script
In the bound spreadsheet: Extensions → Apps Script. For standalone projects, create one at script.google.com and link your Sheet by ID.
- 02
Paste and save
Add a .gs file, paste the code below, rename constants at the top (sheet names, column letters, API property keys), then save.
- 03
Authorize once
Run the main function from the editor. Accept OAuth scopes when prompted — triggers cannot run until authorization succeeds once.
- 04
Add the trigger
Triggers → Add trigger → choose the handler function and event (time-driven, on edit, or on form submit). Delete test triggers before production.
Before you run: create task from form
- 1Tasks sheet created with Description, Owner, DueDate, Status, Source columns
- 2OWNER_ROUTES filled in with request types mapped to owners
- 3DEFAULT_DUE_DAYS set to the team's normal turnaround time
- 4Installable On form submit trigger added for this function
- 5Test submission confirmed for each request type in the routing table
- 6Unassigned fallback tested with a request type missing from OWNER_ROUTES
Frequently asked questions
A sheet-based queue works immediately without extra API enablement and stays easy for a non-technical teammate to review and update.
The row still gets created, but the Owner column shows Unassigned instead of the row being dropped.
Not in this version; dates landing on a weekend are left as calculated, which is worth adjusting if your team does not work weekends.
Yes, once comfortable with the sheet-based queue, the same routing and due-date logic can move onto the Tasks Advanced Service after enabling it in the Services panel.
Add a duplicate-submission guard keyed on timestamp and respondent email, as described in the hardening section.
Yes, add a status-change trigger elsewhere in your workflow that emails the requester when the Status column changes to Done.