Auto-update a Webhook Subscription (PubSubHubbub + YouTube)

After struggling a bit, and getting help here, I came up with this setup to make it easier to maintain a listener for push notifications from the Google PubSubHubbub Hub (and others, possibly).

Maybe there are more efficient ways to achieve this, but I would surely have benefited to find such tips when starting it n8n. I hope it can be useful for others too.

So, basically, you need 2 workflows: the first, is you regular workflow where do you want to run some actions; the second one is a workflow dedicated to subscribe and maintain your webhook updated and working, past the expiration period.

Lets take a look at the second one.

In this example, I setup a webhook to receive notifications every time a YouTube channel uploads or modifies a video.

It uses four kinds of nodes:

  • HTTP Request: to subscribe you webhook.
  • Webhook: to get your subscription verified by the Hub.
  • Cron: so that this workflow runs every 5 days, just before your webhook expires.
  • Set: to hold and format data needed within the workflow.

Copy the code bellow and replace these 3 parameter values in the respective nodes:

  • CHANNEL_ID: the sequence after ‘channel/’ as in https://www.youtube.com/channel/UCiHVTkJtWSdc9N3h0nUGWLg

    • ‘YouTube Settings’ node
  • WEBHOOK_PATH: a random unique alphanumeric sequence. Type anything or get one by adding a fresh webhook node.

    • ‘Webhook Settings’ node
    • ‘Webhook_Subscribe’ node
  • YOUR_DOMAIN: e.g example.com/

    • ‘Webhook Settings’ node
{
  "nodes": [
    {
      "parameters": {},
      "name": "Start",
      "type": "n8n-nodes-base.start",
      "typeVersion": 1,
      "position": [
        550,
        600
      ],
      "disabled": true
    },
    {
      "parameters": {
        "triggerTimes": {
          "item": [
            {
              "mode": "everyX",
              "value": 110
            }
          ]
        }
      },
      "name": "Cron",
      "type": "n8n-nodes-base.cron",
      "typeVersion": 1,
      "position": [
        550,
        200
      ]
    },
    {
      "parameters": {
        "path": "<webhook-path>",
        "responseMode": "lastNode",
        "options": {
          "responsePropertyName": "challenge"
        }
      },
      "name": "Webhook_Subscribe",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [
        550,
        400
      ],
      "webhookId": "314a27ee-7260-4de1-b448-dbbc1decba38"
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "challenge",
              "value": "={{$json[\"query\"][\"hub.challenge\"]}}"
            }
          ]
        },
        "options": {}
      },
      "name": "Verify Webhook",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        850,
        400
      ],
      "executeOnce": false
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "topic_base_url",
              "value": "https://www.youtube.com/xml/feeds/videos.xml?channel_id="
            },
            {
              "name": "domain",
              "value": "<your-domain>"
            },
            {
              "name": "webhook_path",
              "value": "<webhook-path>"
            }
          ]
        },
        "options": {}
      },
      "name": "Webhook Settings",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        950,
        200
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "channel",
              "value": "<channel-id>"
            }
          ]
        },
        "options": {}
      },
      "name": "YouTube Settings",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        750,
        200
      ]
    },
    {
      "parameters": {
        "requestMethod": "POST",
        "url": "https://pubsubhubbub.appspot.com/subscribe",
        "options": {
          "bodyContentType": "form-urlencoded"
        },
        "bodyParametersUi": {
          "parameter": [
            {
              "name": "hub.callback",
              "value": "={{ $node[\"Webhook Settings\"].json[\"domain\"] }}webhook/{{ $node[\"Webhook Settings\"].json[\"webhook_path\"] }}"
            },
            {
              "name": "hub.mode",
              "value": "subscribe"
            },
            {
              "name": "hub.topic",
              "value": "={{$node[\"Webhook Settings\"].json[\"topic_base_url\"]}}{{$node[\"YouTube Settings\"].json[\"channel\"]}}"
            }
          ]
        }
      },
      "name": "Renew Subscription",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 1,
      "position": [
        1150,
        200
      ]
    }
  ],
  "connections": {
    "Cron": {
      "main": [
        [
          {
            "node": "YouTube Settings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook_Subscribe": {
      "main": [
        [
          {
            "node": "Verify Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook Settings": {
      "main": [
        [
          {
            "node": "Renew Subscription",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "YouTube Settings": {
      "main": [
        [
          {
            "node": "Webhook Settings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

After pasting the code in your workflow, modify the parameters, pause the Start node, save the workflow and activate it.
Then, start the workflow by clicking at the small play button atop of the ‘Renew Subscription’ node.

image

To confirm that your Webhook was successfully verified, go to the Google PubSubHubbub Hub and use the Subscriber Diagnostics. Enter with:

After that, click in image and the next page will show the status of the webhook:
image

Now you can close this page and the workflow.

On a new workflow, insert a Webhook node and change the path to the same WEBHOOK_PATH used before.

{
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "WEBHOOK_PATH",
        "options": {
          "responseData": ""
        }
      },
      "name": "Webhook_Push_Notifications",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [
        0,
        0
      ],
      "webhookId": "314a27ee-7260-4de1-b448-dbbc1decba38"
    }
  ],
  "connections": {}
}

Setup the rest of your workflow to take whatever actions and you want from the notifications and you don’t have to worry anymore about this webhook, as long as the previous workflow is active.

1 Like