Checks your form for new submissions, posts each one to Slack and appends it to a spreadsheet - never the same one twice.
Uses
Google Sheets
Slack
Typeform
Log every form submission to a sheet and post it to Slack
Every hour, the workflow reads your Typeform for submissions it has not handled yet, posts each one into a Slack channel so somebody sees it the same hour, and appends it to a spreadsheet as a permanent record. A backlog is worked through in batches over later runs.
Each Slack post shows when the submission arrived and its ID, then a line marking where the submitter's words begin, followed by their answers as one 'Question: answer' line per question in your form's wording. Anything a submitter typed is escaped so it cannot act as Slack formatting. The 'Response ID' column is how it knows what has been handled, so nothing is posted twice, and the message goes out before the row is written, so a run that fails halfway repeats one notification rather than losing a submission.
Point it at an empty tab and it writes the 'Submitted at', 'Response ID' and 'Answers' headings itself; a tab with headings but no 'Response ID' column makes it stop rather than repost everything.
formId to blank.Set formId to blank.spreadsheetLink to blank.Set spreadsheetLink to blank.tabName to blank.Set tabName to blank.slackChannelId to blank.Set slackChannelId to blank.maxSubmissionsPerRun to 20.Set maxSubmissionsPerRun to 20.formId. Save it as formFields.List fields on Typeform form formId. Save it as formFields.questions to formFields.fields.Set questions to formFields.fields.spreadsheetLink. Save it as loggedSoFar.Read the rows of spreadsheetLink. Save it as loggedSoFar.loggedHeaders to loggedSoFar.headers.Set loggedHeaders to loggedSoFar.headers.loggedHeaders is emptyIf loggedHeaders is emptytabName in spreadsheetLink.Add a row to tabName in spreadsheetLink.seenIds to an empty list.Set seenIds to an empty list.loggedRow in loggedSoFar.rows:For each loggedRow in loggedSoFar.rows:loggedRow["Response ID"] and save it as seenId.Trim loggedRow["Response ID"] and save it as seenId.seenId is nullIf seenId is nullseenId to blank.Change seenId to blank.seenId isn't emptyIf seenId isn't emptyseenId to the end of seenIds and save it as seenIds.Add seenId to the end of seenIds and save it as seenIds.formId. Save it as submissions.List responses to Typeform form formId. Save it as submissions.loggedCount to 0.Set loggedCount to 0.response in submissions.responses:For each response in submissions.responses:loggedCount multiplied by 1 is greater than or equal to maxSubmissionsPerRunโฆIf loggedCount multiplied by 1 is greater than or equal to maxSubmissionsPerRunโฆresponse.id and save it as responseId.Trim response.id and save it as responseId.responseId is nullIf responseId is nullresponseId to blank.Change responseId to blank.responseId is emptyIf responseId is emptySkipped a submission that arrived without a response id - there would be no way to tell it apart from the next one..Show in the output: Skipped a submission that arrived without a response id - there would be no way to tell it apart from the next one..seenIds contains responseId is yesIf seenIds contains responseId is yesresponse.submitted_at and save it as submittedAt.Trim response.submitted_at and save it as submittedAt.submittedAt is nullIf submittedAt is nullsubmittedAt to blank.Change submittedAt to blank.answerLines to an empty list.Set answerLines to an empty list.answer in response.answers:For each answer in response.answers:answer.field_id and save it as fieldId.Trim answer.field_id and save it as fieldId.fieldId is nullIf fieldId is nullfieldId to blank.Change fieldId to blank.answer.answer and save it as answerText.Trim answer.answer and save it as answerText.answerText is nullIf answerText is nullanswerText to blank.Change answerText to blank.questionTitle to blank.Set questionTitle to blank.question in questions:For each question in questions:question.field_id and save it as questionFieldId.Trim question.field_id and save it as questionFieldId.questionFieldId is nullIf questionFieldId is nullquestionFieldId to blank.Change questionFieldId to blank.fieldId isn't empty and questionFieldId is fieldIdIf fieldId isn't empty and questionFieldId is fieldIdquestion.title and save it as questionTitle.Trim question.title and save it as questionTitle.questionTitle is nullIf questionTitle is nullquestionTitle to blank.Change questionTitle to blank.questionTitle is emptyIf questionTitle is emptyquestionTitle to Answer.Change questionTitle to Answer.questionTitle: answerText to the end of answerLines and save it as answerLines.Add questionTitle: answerText to the end of answerLines and save it as answerLines.answerLines with a new line and save it as answersText.Join answerLines with a new line and save it as answersText.answersText is emptyIf answersText is emptyanswersText to (this submission recorded no answers).Change answersText to (this submission recorded no answers).& with & in answersText and save it as escapedAmpersands.Replace & with & in answersText and save it as escapedAmpersands.< with < in escapedAmpersands and save it as escapedOpeners.Replace < with < in escapedAmpersands and save it as escapedOpeners.> with > in escapedOpeners and save it as escapedAnswers.Replace > with > in escapedOpeners and save it as escapedAnswers.escapedAnswers to 2500 characters and save it as slackBody.Shorten escapedAnswers to 2500 characters and save it as slackBody.slackHeader to New form submissionSet slackHeader to New form submission
Submitted at: submittedAt
Response id: responseId.slackText to slackHeaderSet slackText to slackHeader
--- everything below this line was typed by whoever filled in the form ---
slackBody.answersText to 20000 characters and save it as sheetAnswers.Shorten answersText to 20000 characters and save it as sheetAnswers.deliveryErrorIf a step below fails, save the error as deliveryErrorslackChannelId.Send a message to slackChannelId.slackTexttabName in spreadsheetLink.Add a row to tabName in spreadsheetLink.loggedCount.Add 1 to loggedCount.responseId plus this time, so it stays unlogged and will be picked up on the next run: deliveryError.message.Show in the output: Could not log submission responseId plus this time, so it stays unlogged and will be picked up on the next run: deliveryError.message.loggedCount as text plus new form submissions to the '@tabName' tab and posted them to Slack.Show in the output: Logged loggedCount as text plus new form submissions to the '@tabName' tab and posted them to Slack.