-
chevron_right
ProcessOne: XMPP integration with n8n
news.movim.eu / PlanetJabber • Yesterday - 16:57 • 7 minutes
n8n is a platform for workflow automation. Let&aposs see how interface n8n workflows with an XMPP network. As an example on how to use XMPP to receive data from n8n, let&aposs build a simple workflow that publishes into a MUC room some information about each commit pushed to a GitHub repository.
Simple workflow to display Git commits in a MUC room
You can browse and download this workflow here: https://share-n8n.net/shared/l6uiZZ54bPC3
GitHub Trigger
To receive the information about each Git push, we use the GitHub Trigger node . You need to set up some GitHub credentials with access to the repository you want to monitor. Then, set the Repository Owner and Repository Name accordingly. The Events you want to receive are of type Push . At this point, you can execute the workflow (just containing this unique node), do a couple of commits on your repository, and push them to test that it&aposs received by the GitHub Trigger node. When it works, pin the output data of the node so you don&apost have to push some more commits while you test the rest of the workflow. Don&apost forget to unpin it once you want to use the workflow for real.
Information Formatting
As you can see in the output data of the
GitHub Trigger
node, the list of commits in the push are in
body.commits
. We use a
Split Out
node
on this field to process each one of these commits.
We then use an
Edit Fields (Set)
node
to format the information we will display about each commit in the final message posted in the MUC room, using a
Manual Mapping
. Just check the input data coming by the previous
Split Out
node to choose what data you want to send to the MUC room. We name the output field
Commit
(type:
String
). Here is an example of such a template:
"{{ $json.message.split(&apos\n&apos)[0] }}" by {{ $json.author.username }} ({{ $json.author.name }} <{{ $json.author.email }}>), {{ $json.modified.length }} modified file{{ $json.modified.length >1 ? "s" : "" }}
The split at the beginning of this example is used to only keep the first line of the commit message.
After that, an Aggregate node will combine the commits info (one per item) into a single item, with this setting:
- Aggregate : Individual Fields
-
Input Field Name
:
Commit(as named in the previous node)
As a result, we&aposll have one item containing the list of commits into a
Commit
field.
ejabberd credentials
We can now send the formatted data to the XMPP server using a
HTTP Request
node
. For that, we use the
send_message
command
from the ejabberd API.
We use an OAuth token to securely call ejabberd API using Bearer Authentication .
Fluux
If you are using a Fluux instance , you can get an OAuth token from your Fluux console, in the API Tokens section.
Self-hosted ejabberd
To create the credentials on your own ejabberd server, you&aposll need to use the
oauth_issue_token
command
to get an OAuth token. Be sure you have an
access rule
that allows you to create such a token.
For the scope parameter of
oauth_issue_token
command, use the one defined in your
api_permissions
acl (
ejabberd:admin
in the example below) and be sure the user you issue the token for has the right to call the
send_message
command.
Extract of an example of an
ejabberd.yml
file that allows to call
send_message
using OAuth:
hosts:
- "process-one.net"
listen:
-
port: 5281
ip: "::"
tls: true
module: ejabberd_http
request_handlers:
"/api": mod_http_api
acl:
admin:
user:
- "admin@process-one.net"
access_rules:
muc:
- allow: all
muc_create:
- allow: local
muc_admin:
- allow: admin
oauth_access:
- allow: admin
api_permissions:
"console commands":
from:
- ejabberd_ctl
who: all
what: "*"
"admin access":
who:
- oauth:
- scope: "ejabberd:admin"
- access:
- allow:
- acl: admin
what:
- send_message
modules:
mod_http_api: {}
mod_muc:
access: muc
access_create: muc_create
access_persistent: muc_create
access_admin: muc_admin
Example of a command to create a token with the above config:
ejabberdctl oauth_issue_token admin@process-one.net 360000 ejabberd:admin
Sending the XMPP message using send_message
Now you can create your credentials in the HTTP Request node:
- Authentication : Predefined Credential Type
- Credential Type : Bearer Auth
- Create a new Bearer Auth and put your token in the Bearer Token field.
For the other fields in the HTTP Request node:
-
Method
:
POST -
URL
: Full URL of the
send_messagecommand as defined by your ejabberd_api listener, for examplehttps://process-one.net:5281/api/send_message. If you are using Fluux , the URL should behttps://NAME.m.in-app.io:5281/api/send_messagewhereNAMEis your Fluux instance name. - Send Body : enabled
-
Body Content Type
:
JSON -
Specify Body
:
Using Fields Below -
Body Parameters
: set the parameters for the
send_messagecommand :-
type:groupchat -
from: bare JID of the bot that will post the message in the MUC room -
to: bare JID of the MUC room -
subject: empty (not relevant for a MUC message) -
body: template to format the commit information. For example, to display the name of the repository followed by the list of commits, one per line:
-
{{ $(&aposGithub Push&apos).item.json.body.repository.full_name }} repository:
{{ $json.Commit.join("\n") }}
The n8n workflow should now be working: it will publish all commits pushed on the repository defined in the first node into the MUC room defined in the last node (don&apost forget to unpin everything).
Same workflow with a custom stanza
You can browse and download this workflow here: https://share-n8n.net/shared/nxmUMbdNM0gH
This is a variant of the above workflow to illustrate how to create and send a custom stanza instead of the simple message that
send_message
API permits. This is needed for example if you want to add an element in a custom namespace into your message stanza.
The minimal stanza for a MUC message is:
<message type="groupchat">
<body>
List of commits
</body>
</message>
We don&apost need to set the
from
,
to
or
id
attribute, it will be handled by the API call done in the last node. Let&aposs say we want to add a sub-tab containing the timestamp of the moment the message was sent by n8n. The stanza we want to create looks like this:
<message type="groupchat">
<body>
List of commits
</body>
<n8n xmlns="p1:custom:timestamp">2025-12-17T11:16:13.071-05:00</n8n>
</message>
Create a custom stanza
We want to create that stanza just before the last one, between the Aggregate node and the HTTP Request node. To ensure that all strings from the git commit are correctly encoded for XML, we use the JSON to XML node . This means we have to construct the stanza in JSON first.
This is done in the Make Stanza in JSON node of type Edit Fields (Set) . We use the Manual Mapping to ensure all special characters from the git commit are correctly escaped.
-
We set a
$field (which is the default Attribute Key ) to set the type attribute on the root element. The name of the root element,message, will be set in the next node, JSON to XML . -
We create a
bodyfield of type String that will contain the list of commits, one per line. We can use the same template used in the last node of the previous workflow:
{{ $(&aposGithub Push&apos).item.json.body.repository.full_name }} repository:
{{ $json.Commit.join("\n") }}
-
We add a
n8nfield for the custom tag, with typeObject, to be able to set axmlnsattribute on it:
{
"_": "{{ $now }}",
"$": {"xmlns": "p1:custom:timestamp"}
}
Convert the stanza in XML
The stanza is converted in XML in the Convert stanza in XML , XML node:
- The Mode is JSON to XML
-
Property Name
is the name of the field in the output data, let&aposs name it
stanza. - We have to enable the Headless option to prevent the XML header to be added before the message.
-
The
Root Name
is set to
message(the root element of the stanza) as the JSON received from the previous node is just the content of the XML document.
Sending the XMPP message using send_stanza
The configuration of the
HTTP Request
node is the same than for the previous workflow, except that the URL must call
send_stanza
instead of
send_message
. The
body
parameter is replaced by the
stanza
one, in which we just have to set the
stanza
field from the previous node:
{{ $json.stanza }}
Be sure to adapt your ejabberd configuration accordingly, specifically to allow
send_stanza
to be called.