⚠️ This version of the docs is deprecated. Looking for the latest features and updates? Explore our latest documentation.

# 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:

Following is an example of a Tweet that we'll richly format and post to Slack:

image-20210518194229746

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:

image-20210518190544989

Select Search Mentions to trigger your workflow every time a new Tweet matches your search criteria:

image-20210518190657509

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.

image-20210518190942880

To complete the trigger setup, add an optional name (e.g., Pipedream Mentions) and click Create Source:

image-20210518191055978

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).

image-20210518191509099

# 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.

image-20210519012640800

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.

image-20210518201050946

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:

image-20210518203135105

# Use an action to post the formatted message to a Slack channel

Next, click + to add a step and select the Slack app:

image-20210525194859085

Then, scroll or search to find the Send Message Using Block Kit action:

image-20210518203402871

To configure the step:

  1. Connect your Slack account
  2. Select the channel where you want to post the message
  3. Set the Blocks field to {{steps.generate_slack_blocks.$return_value}}
  4. 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)

image-20210518204014823

Then Deploy and send a test event to your workflow.

image-20210518204100063

A formatted message should be posted to Slack:

image-20210518204801812

# Run a live test

To run a live test, first turn on your trigger to run the workflow on every new matching Tweet:

image-20210518210047896

Next, post a Tweet mentioning @pipedreamclick 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:

image-20210526180913701

This will bring up the code and configuration for the source (which you can edit). Click on the Events tab:

image-20210526181036217

Finally, click on Run Now

image-20210526181111074

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.