# Real-world Twitter -> Slack
For the last example in this quickstart, we'll use many of the patterns introduced in earlier examples to solve a real-world use case and will cover how to:
- Trigger a workflow anytime @pipedream is mentioned on Twitter
- Construct a message in Node.js using Slack Block Kit
- Use an action to post the formatted message to a Slack channel
- Run a live test
Following is an example of a Tweet that we'll richly format and post to Slack:
TIP
If you didn't complete the previous examples, we recommend you start from the beginning of this guide to learn the basics of workflow development. If you have any issues completing this example, you can view, copy and run a completed version (opens new window).
# Trigger a workflow anytime @pipedream
(opens new window) is mentioned on Twitter
First, create a new workflow and select the Twitter app:
Select Search Mentions to trigger your workflow every time a new Tweet matches your search criteria:
Connect your Twitter account and then enter @pipedream
for the search term. This will trigger your workflow when Pipedream's handle is mentioned on Twitter.
To complete the trigger setup, add an optional name (e.g., Pipedream Mentions
) and click Create Source:
Use the drop-down menu to select the event to help you build your workflow. Here we've selected a recent Tweet that includes an image (so we can incorporate that into our Slack message).
# Construct a message in Node.js using Slack Block Kit
Let's include the following data from the trigger event in our Slack message:
- Tweet text
- Tweet Language
- Tweet URL
- Image (if the Tweet included an image, video or animated GIF)
- Tweet timestamp
- Screen name and profile picture of the user
- Metadata for the user (number of followers, location and description)
- Link to the workflow that generated the Slack message (so it's easy to get to if we need to make changes in the future)
We can use Slack's Block Kit Builder to create a JSON message template with placeholder values (opens new window). Next, we'll use a code step to replace the placeholder values with dynamic references to the event data that triggers the workflow.
The action we will use accepts the array of blocks, so let's extract that and export a populated array from our code step (i.e., we don't need to generate the entire JSON payload).
Add a step to Run Node.js code and name it steps.generate_slack_blocks
.
Next, add the following code to steps.generate_slack_blocks
:
// Require iso-639-1 to convert language codes into human readable names
const ISO6391 = require('iso-639-1')
// Require lodash to help extract values from intermittent fields in the Tweet object
const _ = require('lodash')
// Function to return a friendly language name (or "Unknown") for ISO language codes
function getLanguageName(isocode) {
try { return ISO6391.getName(isocode) }
catch (err) { return 'Unknown' }
}
// Function to format numbers over 1000 from Stack Overflow https://stackoverflow.com/questions/9461621/format-a-number-as-2-5k-if-a-thousand-or-more-otherwise-900
function kFormatter(num) {
return Math.abs(num) > 999 ? Math.sign(num)*((Math.abs(num)/1000).toFixed(1)) + 'k' : Math.sign(num)*Math.abs(num)
}
// Format the Tweet (including line breaks) as a quoted Slack message
const quotedMessage = steps.trigger.event.full_text
.split('\n')
.map(line => `> ${line}`)
.join('\n')
// Construct URLs to reference in the formatted message
const tweetUrl = `https://twitter.com/${steps.trigger.event.user.screen_name}/statuses/${steps.trigger.event.id_str}`
const userUrl = `https://twitter.com/${steps.trigger.event.user.screen_name}/`
/*
Use lodash to get the URL for an image representing the media since
this object is not always present; `trigger.event.entities` will be present
when media — photos, animated GIFs or videos — are attached to the Tweet.
This object should always contain a photo, "even in cases of a video
and GIF being attached to Tweet."
https://developer.twitter.com/en/docs/twitter-api/v1/data-dictionary/object-model/entities
*/
const mediaUrl = _.get(steps, 'trigger.event.entities.media[0].media_url_https')
const mediaType = _.get(steps, 'trigger.event.entities.media[0].type')
// Format the message as Slack blocks - https://api.slack.com/block-kit
const blocks = []
blocks.push({
"type": "section",
"text": {
"type": "mrkdwn",
"text": `*<${tweetUrl}|New Mention> by <${userUrl}|${steps.trigger.event.user.screen_name}> (${steps.trigger.event.created_at}):*\n${quotedMessage}`
},
"accessory": {
"type": "image",
"image_url": steps.trigger.event.user.profile_image_url_https,
"alt_text": "Profile picture"
}
})
console.log(mediaType)
// If the Tweet contains a photo add it to the message
if(mediaUrl && mediaType === 'photo') {
blocks.push({
"type": "image",
"image_url": mediaUrl,
"alt_text": "Tweet Image"
})
}
// Populate the context elements, button and footer
blocks.push({
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": `*User:* ${steps.trigger.event.user.screen_name}`
},
{
"type": "mrkdwn",
"text": `*Followers:* ${kFormatter(steps.trigger.event.user.followers_count)}`
},
{
"type": "mrkdwn",
"text": `*Location:* ${steps.trigger.event.user.location}`
},
{
"type": "mrkdwn",
"text": `*Language:* ${getLanguageName(steps.trigger.event.lang)} (${steps.trigger.event.lang})`
},
{
"type": "mrkdwn",
"text": `*Description:* ${steps.trigger.event.user.description}`
}
]
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "View on Twitter",
"emoji": true
},
"url": tweetUrl
}
]
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": `Sent via <https://pipedream.com/@/${steps.trigger.context.workflow_id}|Pipedream>`
}
]
},
{
"type": "divider"
})
return blocks
Deploy your workflow and send a test event. It should execute successfully and steps.generate_slack_blocks
should return an array of Slack Blocks:
# Use an action to post the formatted message to a Slack channel
Next, click + to add a step and select the Slack app:
Then, scroll or search to find the Send Message Using Block Kit action:
To configure the step:
- Connect your Slack account
- Select the channel where you want to post the message
- Set the Blocks field to
{{steps.generate_slack_blocks.$return_value}}
- Set the Notification Text field to
{{steps.trigger.event.full_text}}
(if you don't provide Notification Text, Slack's new message alerts may be blank or may not work)
Then Deploy and send a test event to your workflow.
A formatted message should be posted to Slack:
# Run a live test
To run a live test, first turn on your trigger to run the workflow on every new matching Tweet:
Next, post a Tweet mentioning @pipedream
— click Post Tweet below to use our pre-written Tweet with an image (this image will be included in your formatted Slack message):
Your workflow will be triggered the next time the Twitter source runs (every 15 minutes by default). You can also trigger your source manually. Click on Edit code and configuration in your trigger step:
This will bring up the code and configuration for the source (which you can edit). Click on the Events tab:
Finally, click on Run Now
Your source will run and emit new Tweets. Each new Tweet will trigger your workflow. Messages should be posted to Slack, and you can return to the workflow to inspect the events.
Congratulations! You completed the quickstart and you're ready to start building workflows on Pipedream! Click Next to learn about Pipedream's advanced features including state management, concurrency and execution rate controls and more.