Skip to content

Instantly share code, notes, and snippets.

Last active Nov 10, 2021
What would you like to do?
Tutorial: AO3 to Discord Using Pipedream

Tutorial: AO3 to Discord Using Pipedream

Discord Embed

This tutorial shows you how to deliver all new fics in an AO3 tag directly to a channel in Discord. I do not recommend doing this for extremely active fandoms, but it can be great for smaller fandoms or rarepairs.

Note: This tutorial will only work for you if you are the Server Owner or have Manage Server permissions. Although this tutorial is not difficult, it does take some time and you must follow the instructions exactly.

Getting Your AO3 RSS FeedConnecting the Feed to Discord Using PipedreamSending to a Thread

Getting Your AO3 RSS Feed

RSS feeds were a very early internet feed of information - news, stories, scholarly articles. They were once relatively popular and sites like Facebook and Twitter offered RSS feeds of updates. RSS feeds post information to an XML file at a specific web address every so often; you only need to place the web address into an RSS reader to see all the posts. In the past, most major browsers and/or email clients had RSS readers built in. Once upon a time, I received my fanfic updates directly in Outlook.

RSS has slowly declined in usage, but LUCKILY, AO3 still offers the feeds, which comes in handy for people wanting to automatically post links to fics from certain tags to tumblr, Twitter, or (in our case) Discord.

  1. In your browser head to AO3. Go to the tag you want to post into your channel.

    Note: AO3 only offers RSS feeds for Fandom, Character, and Relationship tags. They are not available for Additional (aka freeform) Tags .

  2. On the top right hand side you'll see an RSS Feed button. Click that button.

    rss feed

  3. OOPS. You broke AO3. Kidding. Kidding. AO3 is now very scarily showing a ton of XML code. It's fine. You don't need to know or understand what it is. All you need to be able to do is grab the URL (web address) out of the address bar. Set this aside for now.

    address and code

Connecting the Feed to Discord Using Pipedream

This is where the tutorial gets a little intense if you are not super tech savvy, but go slow, and read carefully. I promise this is step-by-step.

  1. Go to Pipedream and sign-up for an account and sign in. Once you're in you should see a dashboard that looks something like the below.

    Pipedream Dashboard

  2. Click on New on the right hand side to create a new workflow to link AO3 to Discord.

  3. Click on the greyed out "Title" on the top left, name the workflow something so you'll know what it is, and click the green check mark that appears to save the name.

    Workflow Name

  4. We're going to start by telling Pipedream where to get our information from - in this case, the AO3 RSS Feed for our tag we want to track. Click in the search bar that says "Search for an app" and type in RSS. Click on the RSS option and then click New Item in Feed.

    RSS Logo

  5. Go back to the AO3 RSS feed you opened in the first step, and copy the URL (web address) out of the address bar. Paste it into the box for Feed URL. That should bring up the other options below.

    Timer: This is how frequently Pipedream will check for new works in your followed tag. The default is set to 15 minutes. The longer this is, the less frequent the feed will post to Discord. HOWEVER, keep in mind that your free Pipedream account does have limitations of 10,000 deployments a month. Each time Pipedream checks an RSS feed that's a deployment. A single 15 minute checked feed will deploy 2,974 times a month in a month with 31 days. If you're setting up more than one feed you may need to increase this number to cause each feed to check less frequently.

    Name: This is the name for the SOURCE. You can name if whatever you want. I suggest using something descriptive for later (I.E Tag Name - AO3). This will be especially helpful if you want to use this RSS feed later with other Pipedream features (to post to a tumblr or twitter, for example).

    FSS Setup

  6. Once this is filled out to your liking click the Create Source button. The section will autofill with information from the latest fic in your tag. On the top right hand side of the section there is an on/off switch. Make sure you turn this on.

    RSS Setup Complete


  7. Our next step is to take the information from the feed, remove the HTML coding, and transform it to markdown (aka Discord Formatting).

    Start by clicking the gray + to add a step. This brings up the Select an Action card. This card allows you to select from all of the various services Pipedream offers, but they're sorted by popularity and searching can be a pain as it only searches at what's visible on the card normally. We want it to search everything.

    On the top middle, click Search All Actions.

    Search All Actions

    And NOW click into "Search for an app" and type HTML.

  8. For me, HTML to Markdown comes up second, but you may have to scroll to find it. Click on this option. (Make sure it says Convert via turndown and looks like the underlined option below.)

    HTML to Markdown

  9. In the HTML box below add {{event["atom:summary"]["#"]}}. Then click add all at the end of the optional line below the box.

    add all

  10. This opens up a bunch of settings fields which tell Pipedream what to replace certain HTML with. Set yours to match the below. (You probably recognize some of these like ** for strong or bold.)

    Markdown Settings 1

    Markdown Settings 2

  11. Now that Pipedream knows how to strip out the HTML for us, we have to tell it what to do with the feed information. We're going to be doing that in two more steps. This first one is separates out the fic data from the feed into various categories, changes it to a format Discord embeds are okay with and adds controls for if data is too long or doesn't exist.

    Click on the gray + to add this step. And this time on the far right side select Run Node.js code.


  12. This will load a coding block for javascript. Click where it says nodejs and rename this step to ao3.

    Note: It is critical you name the next two steps the same as me if you want to be able to use the code I provide without any editing. DO NOT SKIP THE RENAMING STEPS.


    Click into the yellow line of the code block and paste the following code:

   var input = steps.html_to_markdown.$return_value.split(/\r?\n/);

   truncate = function(str, length, ending) {
       if (length == null) {
         length = 1000;
       if (ending == null) {
         ending = '...';
       if (str.length > length) {
         return str.substring(0, length - ending.length) + ending;
       } else {
         return str;

   if(input[2].length > 0) {
       this.summary = truncate(input[2]);
   else {
       this.summary = "*N/A*";
   } = input[0].replace("/users", "")

   if (steps.html_to_markdown.$return_value.includes("Words: ")) {
     var words1 = steps.html_to_markdown.$return_value.split("Words: ");
     var words2 = words1[1].split(",");
     this.words = words2[0];}
     else {
       this.words = "*N/A*";

   if (steps.html_to_markdown.$return_value.includes("Chapters: ")) {
     var ch1 = steps.html_to_markdown.$return_value.split("Chapters: ");
     var ch2 = ch1[1].split(",");
     this.chapters = ch2[0];}
     else {
       this.chapters = "*N/A*";

   if (steps.html_to_markdown.$return_value.includes("Fandoms: ")) {
     var fan1 = steps.html_to_markdown.$return_value.split("Fandoms: ");
     var fan2 = fan1[1].split("*");
     this.fandoms = fan2[0];}
     else {
       this.fandoms = "*N/A*";

   if (steps.html_to_markdown.$return_value.includes("Series: ")) {
     var series1 = steps.html_to_markdown.$return_value.split("Series: ");
     var series2 = series1[1].split("*");
     this.series = series2[0];}
     else {
       this.series = "";

   if (steps.html_to_markdown.$return_value.includes("Rating: ")) {
     var rate1 = steps.html_to_markdown.$return_value.split("Rating: ");
     var rate2 = rate1[1].split("*");
     this.rating = rate2[0];}
     else {
       this.rating = "*N/A*";

   if (steps.html_to_markdown.$return_value.includes("Warnings: ")) {
     var warn1 = steps.html_to_markdown.$return_value.split("Warnings: ");
     var warn2 = warn1[1].split("*");
     this.warnings = warn2[0];}
     else {
       this.warnings = "*N/A*";

   if (steps.html_to_markdown.$return_value.includes("Characters: ")) {
     var char1 = steps.html_to_markdown.$return_value.split("Characters: ");
     var char2 = char1[1].split("*");
     this.characters = truncate(char2[0]);}
     else {
       this.characters = "*N/A*";

   if (steps.html_to_markdown.$return_value.includes("Relationships: ")) {
     var rel1 = steps.html_to_markdown.$return_value.split("Relationships: ");
     var rel2 = rel1[1].split("]");
     var rel3 = rel2[0].slice(1)
     this.relationships = truncate(rel3);}
     else {
       this.relationships = "*N/A*";

   if (steps.html_to_markdown.$return_value.includes("Additional Tags: ")) {
   var tags1 = steps.html_to_markdown.$return_value.split("Additional Tags: ");
   var tags2 = tags1[1];
   this.tags = truncate(tags2);}
     else {
       this.tags = "*N/A*";

   if (steps.html_to_markdown.$return_value.includes("Series: ")) {
     this.desc = + "\n**Series:** " + this.series}
     else {
       this.desc =;

Your final step should look like this:

AO3 Step

  1. Now we have to take our data and put it into an embed that we can use with Discord. Click onto the gray + again and on the right hand side of the Select an action card click Run Node.js code again.

    Rename your card embed, and paste the following code into the code block.

      msg = [
      "title": steps.trigger.event.title,
      "description": steps.ao3.desc,
        "fields": [
            "name": "Words",
            "value": steps.ao3.words,
            "inline": true
            "name": "Chapters",
            "value": steps.ao3.chapters,
            "inline": true
            "name": "\u200b",
            "value": "\u200b",
            "inline": true
            "name": "Rating",
            "value": steps.ao3.rating,
            "inline": true
            "name": "Warnings",
            "value": steps.ao3.warnings,
            "inline": true
            "name": "\u200b",
            "value": "\u200b",
            "inline": true
            "name": "Fandoms",
            "value": steps.ao3.fandoms,
            "inline": false
            "name": "Relationships",
            "value": steps.ao3.relationships,
            "inline": false
            "name": "Characters",
            "value": steps.ao3.characters,
            "inline": false
            "name": "Additional Tags",
            "value": steps.ao3.tags,
            "inline": false
            "name": "Summary",
            "value": steps.ao3.summary,
            "inline": false
      "color": 3092790,
      return msg

Your final step should look like this:


  1. Take a deep breath, you're almost done. Now we actually have to set up to send this info to Discord. Click the gray + to add another step. This time select the Discord Webhook action.

    Discord Webhook

    And then choose the Send Message (Advanced) option. You must select this one and NOT just "Send Message" or "Send Message (Advanced)".

    Send Message (Advanced)

  2. Under auth click on "Select an account", and sign in to Discord. Select the server where you want the feed to post and then choose the channel. Click the Authorize button.

    send message

  3. Paste {{steps.embed.$return_value}} into the Embeds box.

    Note: you can also select the username and avatar_url boxes as well. If so, this will allow you to change the name of the webhook that's posting in your server from Pipedream and the Pipedream logo. You can name it and use whatever avatar you want as long as what you put into the avatar link is a direct image link.

    Your final should look something like this:

    Embed Final

  4. At the top click the Save button and then the Deploy button.

    Save and Deploy

  5. Now to test it!

    Scroll back to the top where you entered your feed information. Click the test banner to expand that section and then click the blue SEND TEST EVENT button.

    Send Test Event

    If everything has worked on the left hand side you should see a blue event with a time and a delay measurement. If you head to Discord, it should have posted your embed!


    Discord Embed

    CONGRATS!!! YOU DID IT. Your workflow will start automatically posting fics from your selected tag into your Discord channel.

Sending to a Thread (Optional)

  1. Create the thread you want to send your feed to.

  2. If you don't have developer mode on, follow these instructions to turn on developer mode in Discord.

  3. Now, go back to the thread you created and right click on it and select "Copy ID".

    Copy ID

  4. Head back over to Pipedream, and in the Send Message (Advanced) step, paste the ID you copied into the Thread ID box.

    Thread ID

  5. Save. Deploy. Send a test event.

That's it! Sending to a thread instead of a channel is that simple!


24 Jul 2021

Posted original tutorial with support for fic title, author, and summary.

28 Jul 2021

Added support for additional fic info like rating, relationship, characters, warnings, etc.

14 Aug 2021

Updated with information to support threads. If you've set this up before, you'll need to update your embed code, delete the final webhook step, and follow the steps from step 14 of Connecting the Feed to Discord Using Pipedream forward.

Known Issues/Limitations

☆ Due to the way AO3 generates their RSS feeds this will only register new and not updated fics.

☆ This webhook can only ever display the first relationship tag due to the way the data comes through the RSS feed and how it has to be parsed. The relationship tags cannot be displayed as links because certain character names break the parsing.

☆ If you run into other issues, please let me know and I'll try to find fixes.


☆ If you have questions or need support, feel free to ask here.

☆ Check out my discord bot Archivist for similar embeds for links you share in servers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment