When you do something with web-hooks, there comes a time you run into problems. You need a service in between. For example this Blog runs with Ghost. The Ghost-Blogging-Platform is relatively new, and they introduced web-hooks a while ago. For example if you publish an post you can trigger something else.

This could be a tweet on Twitter, an old-school E-Mail or you can even let an LED Blink on an Arduino which runs Blynk.

One thing is that if you have an Blog you want to be found by google. The google bot visits your site dependent on many factors. But you can tell the Google-Bot that you have updated your content or released a new blog post.

If you're already a pro, skip the beginner intro.

Introduction for Beginners

This is done via the Google Indexing API.

If you publish a new Post, tell Google that you have a new site to index 

Unfortunately this is what you need but this is not how it works. Ghost supports Webhooks, basically a webhook is a call to another website, in this call you also can deliver some information. The information delivery is usually handled via a json. A JSON is just structured data. Here is the JSON Standard: https://www.json.org/json-en.html

And this is how a JSON would look like:

{
  "firstName": "John",
  "lastName": "Smith",
  "isAlive": true,
  "age": 27,
  "address": {
    "streetAddress": "21 2nd Street",
    "city": "New York",
    "state": "NY",
    "postalCode": "10021-3100"
  },
  "phoneNumbers": [
    {
      "type": "home",
      "number": "212 555-1234"
    },
    {
      "type": "office",
      "number": "646 555-4567"
    }
  ],
  "children": [],
  "spouse": null
}

You have attributes and data. {}is a dictionary like a telephone book and [] is just a list. And then of course you can put a list in a dict and that dict in a dict an so on.

The problem we face now is that Google don't know what to do with the JSON from Ghost. We need a middleman who translates all that stuff. And here comes all that fancy services you may have heard of in play.

Like: Zapier - well I don't really like Zapier, I really like something self hosted, like n8n.

This is how it would look like with n8n:

n8n in between 

Connecting Webhooks

Good Video Tutorial: https://www.youtube.com/watch?v=ovlxledZfM4

So imagine you have already a n8n.io instance up and running. You log into your n8n-instance and then it will look something like this:

n8n Into

Now we know that Ghost supports web hooks. Ghost Web-hook Documentation: https://ghost.org/docs/api/v3/webhooks/. There we have site.changed post.edited, post.published - I think post.published sounds really good. You want to tell Google that you've just published a new post and the google bot should take a look at it.

  1. Now press the big red plus button. Go to the Trigger-Tab and type Web-hook.
  2. There is a menu telling you something about authentication etc. Just click at "Web-hook URLs"
  3. Change HTTP-Method to POST
  4. Copy the url it will look something like this: http://n8n.example.com/webhook/12348239-asdf-4df-a920ae-ee83sdfj29b
  5. Now go to your Ghost Admin Menu: Integrations --> + Add custom Integration click on that
  6. I'll call mine n8n
On the bottom you can create an new Webhook for your custom integration

Call it like: Notify Google on Target URL, put your URL you copied from the n8n Web-hook Node.

Test your Web-hook with Curl on the command line:

curl -X POST -H 'Content-type: application/json' --data '{"text":"Test kekw"}' https://n8n.example.com/webhook/c8fa890f-218d-932f-a0ae-7b1cd66ee77b

First I got this error message:

{"code":404,"message":"The requested webhook "POST c8fa890f-218d-932f-a0ae-7b1cd66ee77b" is not registered."

Be sure that you press the button on the top right "Execute Node" then the node is waiting for a POST request.

curl -X POST -H 'Content-type: application/json' --data '{"text":"Test kekw"}' https://n8n.example.com/webhook-test/c8fa890f-218d-932f-a0ae-7b1cd66ee77b
Response

If that web-hook gets triggered by the web-hook you'll see that Ghost sends the entire Blog-Entry-JSON. We only need the URL from the JSON: ['body']['post']['current']['url']

You can use this JSON for testing and sending it with curl to your n8n-webhook URL:

{
    "post": {
        "current": {
            "url": "https://www.example.com/but-first-coffee/"
        }
    }    
}

Your curl would look like this:

curl -X POST -H 'Content-type: application/json' --data '{
    "post": {
        "current": {
            "url": "https://www.exmaple.com/but-first-coffee/"
        }
    }
}' https://n8n.example.com/webhook-test/bbabab98-2934-4328-1337-34892asfj109

Now we have to extract the data and notify Google that the post has updated. For that we Create a new Node called "HTTP Request".

Google expects an JSON which looks like that:

{
  "url": "content_location",
  "type": "URL_UPDATED"
}
We created parameters called url and type

Now click at the cogs. Add Expression. Then on Current Node --> Input Data --> JSON --> body --> post --> current --> url (to see the url you have to scroll down a bit)

The Expression should look like this:

{{$node["Webhook"].json["body"]["post"]["current"]["url"]}}

In the type field just type: URL_UPDATED.

If you execute this node you'll see the following:

ERROR: 401 - {"error":{"code":401,"message":"Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.","status":"UNAUTHENTICATED"}}

We have to send some credentials to "login". The error message tells us, that we need an OAuth 2 access token.

Getting the Google OAuth2 Access token.

First you need to setup this: https://developers.google.com/search/apis/indexing-api/v3/prereqs

Then this here: https://developers.google.com/identity/protocols/oauth2

Here is a tutorial from google how to create OAuth2: https://developers.google.com/adwords/api/docs/guides/authentication

You need the:

  • Client ID
  • Client Secret

The rest is always the same:

Type in your stuff you got from Google.

If you got the error, that you press the connect button but no popup pops up. Clear all cookies or use Incognito-Tab and try again. And your browser should allow popups for your n8n instance.

Be sure also to set Auth URI Query Parameter to:

access_type=offline&prompt=consent

otherwise you will get an Error: ERROR: No refresh token.

(https://developers.google.com/identity/protocols/oauth2/web-server)

Everything to copy paste:

Authorization URL:  https://accounts.google.com/o/oauth2/auth
Access Token URL:   https://oauth2.googleapis.com/token
Scope:              https://www.googleapis.com/auth/webmasters

On Googles Site:

Redirect URLS: https://sub.example.com/rest/oauth2-credential/callback
Javascript Sources: https://sub.example.com
  • URL for HTTP Request Node: https://indexing.googleapis.com/v3/urlNotifications:publish

Finishing up

Your HTTP Request should look like this:

Success - With the response from google you could create other things.

Complete JSON to import in n8n:

{
  "name": "GhostGoogleURLUpdate",
  "nodes": [
    {
      "parameters": {},
      "name": "Start",
      "type": "n8n-nodes-base.start",
      "typeVersion": 1,
      "position": [
        180,
        490
      ]
    },
    {
      "parameters": {
        "authentication": "oAuth2",
        "requestMethod": "POST",
        "url": "https://indexing.googleapis.com/v3/urlNotifications:publish",
        "options": {},
        "bodyParametersUi": {
          "parameter": [
            {
              "name": "url",
              "value": "={{$node[\"Webhook\"].json[\"body\"][\"post\"][\"current\"][\"url\"]}}"
            },
            {
              "name": "type",
              "value": "URL_UPDATED"
            }
          ]
        },
        "queryParametersUi": {
          "parameter": []
        }
      },
      "name": "HTTP Request",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 1,
      "position": [
        840,
        190
      ],
      "credentials": {
        "oAuth2Api": "n8n4"
      }
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "",
        "options": {}
      },
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [
        550,
        190
      ],
      "webhookId": ""
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "HTTP Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {},
  "id": "1"
}

If you found this in any way helpful :) please comment below I would really appreaciate your input <3

Thanks :)