Checks your form for new submissions, posts each one to Slack and appends it to a spreadsheet - never the same one twice.

UsesGoogle SheetsSlackTypeform

Log every form submission to a sheet and post it to Slack

ScheduleRun every hour.Run every hour.
ValuesSet formId to blank.Set formId to blank.
ValuesSet spreadsheetLink to blank.Set spreadsheetLink to blank.
ValuesSet tabName to blank.Set tabName to blank.
ValuesSet slackChannelId to blank.Set slackChannelId to blank.
ValuesSet maxSubmissionsPerRun to 20.Set maxSubmissionsPerRun to 20.
TypeformTypeformList fields on Typeform form formId. Save it as formFields.List fields on Typeform form formId. Save it as formFields.
ValuesSet questions to formFields.fields.Set questions to formFields.fields.
Google SheetsGoogle SheetsRead the rows of spreadsheetLink. Save it as loggedSoFar.Read the rows of spreadsheetLink. Save it as loggedSoFar.
ValuesSet loggedHeaders to loggedSoFar.headers.Set loggedHeaders to loggedSoFar.headers.
Decisions & LoopsIf loggedHeaders is emptyIf loggedHeaders is empty
Yes
Google SheetsGoogle SheetsAdd a row to tabName in spreadsheetLink.Add a row to tabName in spreadsheetLink.
Else if @loggedHeaders doesn't contain "Response ID"
Decisions & LoopsStop and report a problem: The tab named in the 'tabName' step needs a column headed exactly 'Response ID'. Without it this workflow cannot tell which submissions it has already handled, and it would post every one of them again on every run. Point 'tabName' at an empty tab and it will write the headings itself.Stop and report a problem: The tab named in the 'tabName' step needs a column headed exactly 'Response ID'. Without it this workflow cannot tell which submissions it has already handled, and it would post every one of them again on every run. Point 'tabName' at an empty tab and it will write the headings itself.
Otherwise
No steps
ValuesSet seenIds to an empty list.Set seenIds to an empty list.
Decisions & LoopsFor each loggedRow in loggedSoFar.rows:For each loggedRow in loggedSoFar.rows:
TextTrim loggedRow["Response ID"] and save it as seenId.Trim loggedRow["Response ID"] and save it as seenId.
Decisions & LoopsIf seenId is nullIf seenId is null
Yes
ValuesChange seenId to blank.Change seenId to blank.
No
No steps
Decisions & LoopsIf seenId isn't emptyIf seenId isn't empty
Yes
ListsAdd seenId to the end of seenIds and save it as seenIds.Add seenId to the end of seenIds and save it as seenIds.
No
No steps
TypeformTypeformList responses to Typeform form formId. Save it as submissions.List responses to Typeform form formId. Save it as submissions.
ValuesSet loggedCount to 0.Set loggedCount to 0.
Decisions & LoopsFor each response in submissions.responses:For each response in submissions.responses:
Decisions & LoopsIf loggedCount multiplied by 1 is greater than or equal to maxSubmissionsPerRunโ€ฆIf loggedCount multiplied by 1 is greater than or equal to maxSubmissionsPerRunโ€ฆ
Yes
Decisions & LoopsStop repeating.Stop repeating.
No
No steps
TextTrim response.id and save it as responseId.Trim response.id and save it as responseId.
Decisions & LoopsIf responseId is nullIf responseId is null
Yes
ValuesChange responseId to blank.Change responseId to blank.
No
No steps
Decisions & LoopsIf responseId is emptyIf responseId is empty
Yes
ValuesShow 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..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..
Decisions & LoopsSkip to the next item.Skip to the next item.
No
No steps
Decisions & LoopsIf seenIds contains responseId is yesIf seenIds contains responseId is yes
Yes
Decisions & LoopsSkip to the next item.Skip to the next item.
No
No steps
TextTrim response.submitted_at and save it as submittedAt.Trim response.submitted_at and save it as submittedAt.
Decisions & LoopsIf submittedAt is nullIf submittedAt is null
Yes
ValuesChange submittedAt to blank.Change submittedAt to blank.
No
No steps
ValuesSet answerLines to an empty list.Set answerLines to an empty list.
Decisions & LoopsFor each answer in response.answers:For each answer in response.answers:
TextTrim answer.field_id and save it as fieldId.Trim answer.field_id and save it as fieldId.
Decisions & LoopsIf fieldId is nullIf fieldId is null
Yes
ValuesChange fieldId to blank.Change fieldId to blank.
No
No steps
TextTrim answer.answer and save it as answerText.Trim answer.answer and save it as answerText.
Decisions & LoopsIf answerText is nullIf answerText is null
Yes
ValuesChange answerText to blank.Change answerText to blank.
No
No steps
ValuesSet questionTitle to blank.Set questionTitle to blank.
Decisions & LoopsFor each question in questions:For each question in questions:
TextTrim question.field_id and save it as questionFieldId.Trim question.field_id and save it as questionFieldId.
Decisions & LoopsIf questionFieldId is nullIf questionFieldId is null
Yes
ValuesChange questionFieldId to blank.Change questionFieldId to blank.
No
No steps
Decisions & LoopsIf fieldId isn't empty and questionFieldId is fieldIdIf fieldId isn't empty and questionFieldId is fieldId
Yes
TextTrim question.title and save it as questionTitle.Trim question.title and save it as questionTitle.
Decisions & LoopsStop repeating.Stop repeating.
No
No steps
Decisions & LoopsIf questionTitle is nullIf questionTitle is null
Yes
ValuesChange questionTitle to blank.Change questionTitle to blank.
No
No steps
Decisions & LoopsIf questionTitle is emptyIf questionTitle is empty
Yes
ValuesChange questionTitle to Answer.Change questionTitle to Answer.
No
No steps
ListsAdd 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.
TextJoin answerLines with a new line and save it as answersText.Join answerLines with a new line and save it as answersText.
Decisions & LoopsIf answersText is emptyIf answersText is empty
Yes
ValuesChange answersText to (this submission recorded no answers).Change answersText to (this submission recorded no answers).
No
No steps
TextReplace & with & in answersText and save it as escapedAmpersands.Replace & with & in answersText and save it as escapedAmpersands.
TextReplace < with &lt; in escapedAmpersands and save it as escapedOpeners.Replace < with &lt; in escapedAmpersands and save it as escapedOpeners.
TextReplace > with &gt; in escapedOpeners and save it as escapedAnswers.Replace > with &gt; in escapedOpeners and save it as escapedAnswers.
TextShorten escapedAnswers to 2500 characters and save it as slackBody.Shorten escapedAnswers to 2500 characters and save it as slackBody.
ValuesSet slackHeader to New form submissionSet slackHeader to New form submission Submitted at: submittedAt Response id: responseId.
ValuesSet slackText to slackHeaderSet slackText to slackHeader --- everything below this line was typed by whoever filled in the form --- slackBody.
TextShorten answersText to 20000 characters and save it as sheetAnswers.Shorten answersText to 20000 characters and save it as sheetAnswers.
Decisions & LoopsIf a step below fails, save the error as deliveryErrorIf a step below fails, save the error as deliveryError
Try
SlackSlackSend a message to slackChannelId.Send a message to slackChannelId.slackText
Google SheetsGoogle SheetsAdd a row to tabName in spreadsheetLink.Add a row to tabName in spreadsheetLink.
ValuesAdd 1 to loggedCount.Add 1 to loggedCount.
On error
ValuesShow 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.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.
ValuesShow in the output: Logged 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.