In this “How To” I’m going to show you how to build a Trello Power-Up that will allow users to search for and embed YouTube videos in their cards. We’ll be using Trello, GitHub, and YouTube. When we’re done, you’ll be able to create cards that look like this:

I’ll walk you through the process step by step, but you can also see the full code for the project on GitHub. I also recommend you refer to the Power-Up documentation before you begin.
GitHub Set Up
Let’s get started with GitHub. If you don’t have an account, you can create one at github.com. Once your account is created and you are logged in you will also need to set up your GitHub Pages website since that is where we’ll be hosting our Power-Up. Follow the instructions at pages.github.com to set up GitHub Pages. Now when you create a new GitHub repository it will be hosted at https://yourusername.github.io/your-repository-name. Pretty cool, right?
Fork the Power-Up Template
Now that GitHub is set up, let’s get started with the Power-Up! The easiest way to start building a new Power-Up is to fork Trello’s template project which is a full featured sample Power-Up. Go to the power-up-template repository and click the “Fork” button in the upper right corner of the page. I gave my fork a new name (youtube-power-up) and description. Then clone the repository to get a local copy. I like working with GitHub Desktop.
Update the Manifest
Next we’re going to edit the manifest to reflect that this is a YouTube Power-Up. Open up manifest.json in your favorite editor. We’ll edit the name, description, details, icon, author, and capabilities. Notice that I changed the url of the icon, that’s because we’re going to use the official YouTube icon instead of the icons that came with the template. The other section to pay attention to is the “capabilities”. I recommend reading more about capabilities here, but for now you need to know that we’ll be using attachment-sections, card-buttons, and callbacks. My finished manifest looks like this:
{
"name": "YouTube",
"description": "A Power-Up for integrating YouTube content in your cards",
"details": "This Power-Up is used for integrating YouTube content in your cards",
"icon": {
"url": "./images/yt_icon_rgb.png"
},
"author": "Amber Ream",
"capabilities": [
"attachment-sections",
"callback",
"card-buttons"
],
"connectors": {
"iframe": {
"url": "./index.html"
}
}
}
Be sure to add the YouTube icon to your images folder. When you’re done with your edits, push your changes to the manifest and the new icon to GitHub.
Create a new Power-Up in Trello
Now we’re ready to create the new Power-Up in Trello. If you don’t already have a Trello account, sign up for one at trello.com. Since Power-Ups are associated with teams, you’ll also need to create a new team. You can do this by clicking the “Create a new team…” link underneath your boards.

Now you’re ready to create a new Power-Up from the Power-Ups Administration Page. Under “Teams” click on the team you’d like to add the Power-Up to, then choose “Create new Power-Up”. Give your Power-Up a name (I chose YouTube Power-Up) and then enter the path to manifest.json. If you’re using GitHub Pages, the url will look something like this:
https://username.github.io/repository-name/manifest.json
Click save and your new Power-Up will show up in the list of Power-Ups.
Add the Power-Up to a Board
Now that our Power-Up has been created, let’s go to our boards so we can add our Power-Up and see it in action! At this point it will have the template functionality, we’ll implement the YouTube code later. To add the Power-Up to a board, go back to trello.com and if you haven’t already created a board for your team go ahead and do that now. Then click on your board to open it. To add the Power-Up, go to your team’s board and choose “Power-Ups” from the menu.

Scroll down and you should find the new “YouTube” Power-Up in the list (it is sorted alphabetically). Note that the name, details, and icon you see in the Power-Up list are all coming from manifest.json. Click “enable” to enable this Power-Up (if you are using the free version of Trello only one Power-Up is allowed per board so you may need to disable another Power-Up first). I’ve noticed it can take anywhere from a few minutes to a few hours for the Power-Up’s icon & description to show up in the list, so don’t worry if all you see is the name at this point! Likewise there is some lag before the Power-Up is available in your cards. In the meantime, we can get started on other parts of our project.
YouTube API
We will be using the YouTube Data API to search for videos. Before we can connect to the API, we’ll have to set up credentials and grant access to the YouTube Data API. Make a note of your API key because you’ll be using it soon, and please remember to restrict your API key! For example, I chose to only allow YouTube requests coming from my GitHub Pages site.

Implement client.js
Now it’s time to make our Power-Up do something! But first, a little set up. Since I like to use jQuery for ajax requests, I’m going to import it in index.html.
<script src=”http://code.jquery.com/jquery-3.2.1.min.js”integrity=”sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=” crossorigin=”anonymous”></script>
Next, since I have a custom icon that I would like to display for the YouTube Power-Up on the back of the card, let’s drop the gray play button icon in the images folder.
You may remember defining card-buttons, attachment-sections, and callback in manifest.json. Let’s take a look at how those are used in client.js. We don’t have to define anything specifically for “callback” here, but you can read more about why we need the “callback” defined in the manifest here.
card-buttons
We’ll start by adding a button to the back of our card. In client.js, find the ‘card-buttons‘ function inside TrelloPowerUp.initialize. We will need to define a button that will trigger the YouTube Power-Up. We’ll give it an icon, text, and a callback function that will be called when the button is clicked. This button will be using the gray play button icon, so you’ll need to update the GRAY_ICON constant at the top of the file to refer to the gray icon you just added to the images folder.
var GRAY_ICON = './images/yt_icon_gray.png';
We can also remove the template code since we won’t be using it, so when we’re finished, our card-buttons function will look like this:
'card-buttons': function(t, options) {
return [{
// YouTube!
icon: GRAY_ICON,
text: 'YouTube',
callback: youTubeButtonCallback
}];
}
Now we need to define the youTubeButtonCallback. This is where we’ll display a popup so the user can search for a video on YouTube. We’ll make requests to the YouTube Data API as the user types and then return a list of results that will get displayed in our popup. In the code below we’re using jQuery to make a request to the YouTube Data API to get a list of results based on what the user has typed into the search box. Each result contains “text” and “callback” properties. The text is what gets displayed in the list, and the callback is the function that gets called when an item in the list is clicked. In this case, we want to attach the YouTube video to the card. Remember to update the YouTube key to your own key which you created above or searching will fail!
var youTubeButtonCallback = function (t) {
return t.popup({
title: 'YouTube',
items: function (t, options) {
// use options.search which is the search text entered so far
// return a Promise that resolves to an array of items
// similar to the items you provided in the client side version above
var response = $.ajax({
url: "https://www.googleapis.com/youtube/v3/search",
data: {
maxResults: '25',
q: options.search,
type: 'video',
part: 'snippet',
key: 'AIzaSyCawso6-SQJS2JAw7FCXQD-sNeLtzDPxE0'
},
success: function (data) {
// console.log(data);
},
error: function (jqXHR, textStatus, errorThrown) {
alert(errorThrown);
}
});
// when the response is finished, then return a list of items
return response.then(function (data) {
// console.log(data);
var ret = new Array();
var items = data.items;
for (var i = 0; i < items.length; i++) {
ret.push({
text: items[i].snippet.title,
callback: (function (item) {
return function (t, opts) {
return t.attach({
name: item.snippet.title, // optional
url: "https://www.youtube.com/embed/" + item.id.videoId // required
});
}
})(items[i])
});
}
return ret;
});
},
search: {
// optional # of ms to debounce search to
// defaults to 300, override must be larger than 300
debounce: 300,
placeholder: 'Search',
empty: 'No results',
searching: 'Searching'
}
});
};
attachment-sections
On to "attachment-sections"! This is what defines how the YouTube url we are attaching in the YouTube callback will get displayed on the card. There are three files that need to be updated, let's start with section.html. In this file we're simply defining a container to hold our YouTube videos:
<body>
<div id="content">
<div id="videos"></div>
</div>
<script src="./js/section.js"></script>
</body>
Notice the section.js import. This is the next file we need to edit. Let's look at the render function:
t.render(function () {
// make sure your rendering logic lives here, since we will
// recall this method as the user adds and removes attachments
// from your section
t.card('attachments')
.get('attachments')
.filter(function (attachment) {
return attachment.url.indexOf('https://www.youtube.com') == 0;
})
.then(function (youtubeAttachments) {
var urls = youtubeAttachments.map(function (a) {
return '<div class="video"><iframe src="' + a.url + '?rel=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe></div>';
});
document.getElementById('videos').innerHTML = urls.join(' ');
})
.then(function () {
return t.sizeTo('#content');
});
});
Since we are interested in embedding YouTube videos, we're filtering for urls that begin with "https://www.youtube.com". For each video we find, we're adding a new iframe and adding it to the videos div that we defined in section.html. Finally, we need to update the "attachment-sections" function in client.js.
'attachment-sections': function (t, options) {
// options.entries is a list of the attachments for this card
// you can look through them and 'claim' any that you want to
// include in your section.
// we will just claim urls for YouTube
var claimed = options.entries.filter(function (attachment) {
// claim youtube urls
return attachment.url.indexOf('https://www.youtube.com') === 0;
});
// you can have more than one attachment section on a card
// you can group items together into one section, have a section
// per attachment, or anything in between.
if (claimed && claimed.length > 0) {
// if the title for your section requires a network call or other
// potentially length operation you can provide a function for the title
// that returns the section title. If you do so, provide a unique id for
// your section
return [{
id: 'YouTube', // optional if you aren't using a function for the title
claimed: claimed,
icon: YOUTUBE_ICON,
title: 'YouTube Videos',
content: {
type: 'iframe',
url: t.signUrl('./section.html', {
arg: 'you can pass your section args here'
}),
height: 230
}
}];
} else {
return [];
}
}
As in section.js we need a filter for urls that begin with "https://www.youtube.com" because these are the only urls we want to include in our YouTube attachment section. The "id" will be the name of the attachment section, and the "icon" will show up next to the name. We are using the standard YouTube icon here, so we'll need to create a constant at the top of our file that points to the red YouTube icon.
var YOUTUBE_ICON = './images/yt_icon_rgb.png';
Code Cleanup
You're done with the hard part! Since we cloned this project from the sample codebase there is a lot of code we don't need, so let's delete it. Starting with client.js, there are several hooks defined that we're not using. You can delete everything except "card-buttons" and "attachment-sections". In client.js we can also get rid of the callback functions we're not using (just be sure to keep the youTubeButtonCallback).
All done!
That's it! Go back to trello.com, open up your board, and if you don't already have a card you should create one. Then when you edit your card you will see the YouTube button on the right side of the card under "Power-Ups". When you click the button, the search popup will come up and you can start searching for a YouTube video. Click on the name of the video you want to embed, and Voila, it will appear near the top of your card under the YouTube heading.
Congratulations on completing your YouTube Power-Up!