Extract data from workflow to Open WebUI

Hi there,

We are using Open WebUI as a chat platform, and would like to integrate to n8n.
We are able to send a chat message to a webhook in an n8n workflow, but how do we extract the response?
The simple workflow below is the one we are testing with currently.

Best regards
Claus

It looks like your topic is missing some important information. Could you provide the following if applicable.

  • n8n version:
  • Database (default: SQLite):
  • n8n EXECUTIONS_PROCESS setting (default: own, main):
  • Running n8n via (Docker, npm, n8n cloud, desktop app):
  • Operating system:

Hi @Clausladefoged ,

Welcome to the community! :icecream:

You could set your webhook to respond to a “respond to webhook” node, so that you get the answer after the data has been parsed through the AI node cluster.
You will still need to adjust how you want the response data, based on what you’re parsing and the specificities of WebUI. You can do that in the “respond to webhook” node.

You can also read more about how this node works in our docs - Webhook node documentation | n8n Docs

1 Like

I can’t link openwebui and n8n with a webhook. Openwebui always uses ollama container to generate the response. Any suggestions to use openwebui as frontend?

Thank you @mariana-na!
That was just what I needed, and I now have a working pipeline from Open WebUI to n8n.

1 Like

Claus, I am trying to do this same thing and have a workflow that works with Postman but I haven’t been successful in getting it linked to Open WebUI. Every time I try to provide it the webhook URL for Ollama it fails. Would you mind sharing how are you connecting it in Open WebUI?

@dping28 Sure. I made a very simple workflow below just for the sake of testing:

Below is the code for the pipeline in Open WebUI. You just need to add your own credentials in the “PlaceYourOwnHere”. Hope it works for you.

–

from typing import List, Union, Generator, Iterator, Callable, Any
from schemas import OpenAIChatMessage
import subprocess
import requests
import json
from urllib.parse import urlparse, urljoin
from pydantic import BaseModel, Field
import asyncio
import os
import uuid

class N8NAPIClient:
def init(self, N8N_API_BASE_URL: str, N8N_API_KEY: str) → None:
if not N8N_API_BASE_URL.startswith((‘http://’, ‘https://’)):
N8N_API_BASE_URL = ‘https://’ + N8N_API_BASE_URL
self.n8n_base_url = N8N_API_BASE_URL
self.n8n_api_key = N8N_API_KEY

def get_workflow(self, workflow_id: str) -> dict[str, Any]:
    return self.GET(path=f'/api/v1/workflows/{workflow_id}')

def get_execution(self, workflow_id: str, execution_id: str):
    return self.GET(path=f'/api/v1/executions/{execution_id}')

def trigger_webhook(self, webhook_id: str, input: str):
    return self.POST(path=f'/webhook-test/{webhook_id}', data=input)

def chat(self, webhook: str, session_id: str, input: str):
    return self.POST(path=f'/webhook/{webhook}/chat', data=json.dumps({
        "action": "sendMessage",
        "sessionId": session_id,
        "chatInput": input,
    }))

def POST(self, path: str, data: str) -> None:
    headers = {
        'content-type': 'application/json',
        "x-n8n-api-key": self.n8n_api_key,
        "cookie": f'n8n-auth={self.n8n_api_key}'
    }
    url = f'{self.n8n_base_url}{"//" if not path.startswith("/") else ""}{path}'
    
    # Validate URL
    parsed_url = urlparse(url)
    if not all([parsed_url.scheme, parsed_url.netloc]):
        raise ValueError(f"Invalid URL: {url}. Make sure it includes a scheme (http:// or https://) and a domain.")
    
    resp = requests.post(url, headers=headers, data=data)
    resp.raise_for_status()
    return resp.json()

def GET(self, path: str) -> None:
    headers = {
        "x-n8n-api-key": self.n8n_api_key,
        "cookie": f'n8n-auth={self.n8n_api_key}'
    }
    url = f'{self.n8n_base_url}{"//" if not path.startswith("/") else ""}{path}'
    
    # Validate URL
    parsed_url = urlparse(url)
    if not all([parsed_url.scheme, parsed_url.netloc]):
        raise ValueError(f"Invalid URL: {url}. Make sure it includes a scheme (http:// or https://) and a domain.")
    
    resp = requests.get(url, headers=headers)
    resp.raise_for_status()
    return resp.json()

class Pipeline:
class Values(BaseModel):
N8N_API_BASE_URL: str = “”
N8N_API_KEY: str = “”
N8N_WORKFLOW_ID: str = “”

def __init__(self):
    self.name = "N8N sample pipeline"
    self.values = self.Values(
        **{
            'N8N_API_BASE_URL': os.getenv("N8N_API_BASE_URL", "PlaceYourOwnHere"),
            'N8N_API_KEY': os.getenv("N8N_API_KEY", "PlaceYourOwnHere"),
            'N8N_WORKFLOW_ID': os.getenv("N8N_WORKFLOW_ID", "PlaceYourOwnHere"),
        }
    )
    self.n8n = N8NAPIClient(N8N_API_BASE_URL=self.values.N8N_API_BASE_URL,
                            N8N_API_KEY=self.values.N8N_API_KEY)

async def on_startup(self):
    # This function is called when the server is started.
    print(f"on_startup:{self.name}")
    pass

async def on_shutdown(self):
    # This function is called when the server is stopped.
    print(f"on_shutdown:{self.name}")
    pass

def pipe(
    self, user_message: str, model_id: str, messages: List[dict], body: dict
) -> Union[str, Generator, Iterator]:
    # better to get the workflow id from a parameter here but just doing a quick and dirty approach here
    #session_id = 'a191a4f1-4802-4dcf-8ded-07f3a82711f7' 
    session_id = str(uuid.uuid4()) # this should probably be unique per chat session to keep state, here we generate a new session id each time we call the chat function
    response = self.n8n.chat(webhook='PlaceYourOwnHere', session_id=session_id, input=user_message)
    return response['output']
1 Like

Thank you so much Claus! I am extremely new to all this and didnt even know about the pipelines but with your code and perplexity I managed to make a version of the pipeline that worked with my setup and basic webhook workflow through Open-WebUI!

2 Likes

I am getting “Uh-oh! There was an issue connecting to N8N sample pipeline.
network error”.
I just saved the .py file and imported it in openwebui, and selected that as chat model.
Any idea @Clausladefoged @dping28 ? :heavy_heart_exclamation: for the help!!!

I have used this:

from typing import List, Union, Generator, Iterator, Any
from schemas import OpenAIChatMessage
import requests
import json
from urllib.parse import urlparse
from pydantic import BaseModel
import os
import uuid

class N8NAPIClient:
    def __init__(self, N8N_API_BASE_URL: str, N8N_API_KEY: str) -> None:
        if not N8N_API_BASE_URL.startswith(('http://', 'https://')):
            N8N_API_BASE_URL = 'https://' + N8N_API_BASE_URL
        self.n8n_base_url = N8N_API_BASE_URL
        self.n8n_api_key = N8N_API_KEY

    def get_workflow(self, workflow_id: str) -> dict[str, Any]:
        return self.GET(path=f'/api/v1/workflows/{workflow_id}')

    def get_execution(self, workflow_id: str, execution_id: str):
        return self.GET(path=f'/api/v1/executions/{execution_id}')

    def trigger_webhook(self, webhook_id: str, input: str):
        return self.POST(path=f'/webhook-test/{webhook_id}', data=input)

    def chat(self, webhook: str, session_id: str, input: str):
        return self.POST(path=f'/webhook/{webhook}/chat', data=json.dumps({
            "action": "sendMessage",
            "sessionId": session_id,
            "chatInput": input,
        }))

    def POST(self, path: str, data: str) -> None:
        headers = {
            'content-type': 'application/json',
            "x-n8n-api-key": self.n8n_api_key,
            "cookie": f'n8n-auth={self.n8n_api_key}'
        }
        url = f'{self.n8n_base_url}{"//" if not path.startswith("/") else ""}{path}'

        # Validate URL
        parsed_url = urlparse(url)
        if not all([parsed_url.scheme, parsed_url.netloc]):
            raise ValueError(f"Invalid URL: {url}. Make sure it includes a scheme (http:// or https://) and a domain.")

        resp = requests.post(url, headers=headers, data=data)
        resp.raise_for_status()
        return resp.json()

    def GET(self, path: str) -> None:
        headers = {
            "x-n8n-api-key": self.n8n_api_key,
            "cookie": f'n8n-auth={self.n8n_api_key}'
        }
        url = f'{self.n8n_base_url}{"//" if not path.startswith("/") else ""}{path}'

        # Validate URL
        parsed_url = urlparse(url)
        if not all([parsed_url.scheme, parsed_url.netloc]):
            raise ValueError(f"Invalid URL: {url}. Make sure it includes a scheme (http:// or https://) and a domain.")

        resp = requests.get(url, headers=headers)
        resp.raise_for_status()
        return resp.json()


class Pipeline:
    class Values(BaseModel):
        N8N_API_BASE_URL: str = ""
        N8N_API_KEY: str = ""
        N8N_WORKFLOW_ID: str = ""

    def __init__(self):
        self.name = "N8N sample pipeline"
        self.values = self.Values(
            **{
                'N8N_API_BASE_URL': os.getenv("N8N_API_BASE_URL", "http://host.docker.internal:5678/"),
                'N8N_API_KEY': os.getenv("N8N_API_KEY", "n8n_api_hj123712863kj123y781237612--------------"),
                'N8N_WORKFLOW_ID': os.getenv("N8N_WORKFLOW_ID", "Kasdfasdf121232"),
            }
        )
        self.n8n = N8NAPIClient(N8N_API_BASE_URL=self.values.N8N_API_BASE_URL,
                                N8N_API_KEY=self.values.N8N_API_KEY)

    async def on_startup(self):
        # This function is called when the server is started.
        print(f"on_startup:{self.name}")
        pass

    async def on_shutdown(self):
        # This function is called when the server is stopped.
        print(f"on_shutdown:{self.name}")
        pass

    def pipe(
        self, user_message: str, model_id: str, messages: List[dict], body: dict
    ) -> Union[str, Generator, Iterator]:
        # Generate a new session id for each chat session to keep the state
        session_id = str(uuid.uuid4())  
        
        # Trigger the n8n webhook and pass user input
        response = self.n8n.chat(webhook='http://localhost:5678/webhook-test/b17af5-----------', session_id=session_id, input=user_message)
        
        # Return the output from the webhook
        return response['output']

I have my pipeline setup running in Docker, how about you?

Yes, I did add a pipeline container in the same docker, via adding this to the composed yml file:

Adding Pipelines Service for OpenWebUI

pipelines:
image: Package pipelines ¡ GitHub
container_name: pipelines
networks: [‘demo’]
restart: always
ports:
- 9099:9099 # Exposing pipelines API
volumes:
- pipelines_storage:/app/pipelines # Persistent volume for pipelines
environment:
- PIPELINES_URLS=“pipelines/examples/filters/detoxify_filter_pipeline.py at main · open-webui/pipelines · GitHub” # Example pipeline URL
extra_hosts:
- “host.docker.internal:host-gateway” # Needed for Docker network

I’m getting this error in openwebui container:

2024-10-17 18:03:14   File "/app/backend/open_webui/apps/openai/main.py", line 474, in generate_chat_completion
2024-10-17 18:03:14     r.raise_for_status()
2024-10-17 18:03:14   File "/usr/local/lib/python3.11/site-packages/aiohttp/client_reqrep.py", line 1121, in raise_for_status
2024-10-17 18:03:14     raise ClientResponseError(
2024-10-17 18:03:14 aiohttp.client_exceptions.ClientResponseError: 500, message='Internal Server Error', url='http://pipelines:9099/chat/completions'

And if I try to open http://pipelines:9099/chat/completions in browser, I get {“detail”:“Method Not Allowed”} …is this normal?

Instead when looking at the pipelines container log, I see:

2024-10-17 18:03:14   File "/app/./pipelines/openwebui_to_n8n - GPT.py", line 47, in POST
2024-10-17 18:03:14     resp.raise_for_status()
2024-10-17 18:03:14   File "/usr/local/lib/python3.11/site-packages/requests/models.py", line 1024, in raise_for_status
2024-10-17 18:03:14     raise HTTPError(http_error_msg, response=self)
2024-10-17 18:03:14 requests.exceptions.HTTPError: 404 Client Error: Not Found for url: http://n8n:5678/webhook/b17af545-0f91-4341-8c8c-6a4a36548745/chat

And when I try to open http://n8n:5678/webhook/b17af545-0f91-4341-8c8c-6a4a36548745/chat , I get:

{
  "code": 404,
  "message": "The requested webhook \"GET b17af545-0f91-4341-8c8c-6a4a36548745/chat\" is not registered.",
  "hint": "The workflow must be active for a production URL to run successfully. You can activate the workflow using the toggle in the top-right of the editor. Note that unlike test URL calls, production URL calls aren't shown on the canvas (only in the executions list)"
}

Any idea @Clausladefoged @dping28 ? I’m getting crazy…Can’t understand what’s wrong! The url are all correct (i have containerized all services that’s why I access them via their name instead of “localhost”)…

Looking at the error message it looks as if the workflow is inactive. Have you activated the workflow?

It was activated - in the end, it was the first webook that needed to be a POST and not a GET…I thought it was right because you have set yours to GET in what you shared.
Hope this will help future users!
I also had to change in the .py the following:

class N8NAPIClient:
    def __init__(self, N8N_API_BASE_URL: str, N8N_API_KEY: str) -> None:
        if not N8N_API_BASE_URL.startswith(('http://', 'https://')):
            N8N_API_BASE_URL = 'http://' + N8N_API_BASE_URL #http instead of https
    def chat(self, webhook: str, session_id: str, input: str):
        return self.POST(path=f'/webhook/{webhook}', data=json.dumps({  # /chat removed at the end of the path
            "action": "sendMessage",
            "sessionId": session_id,
            "chatInput": input,
        }))

However, I beileve we need some edit fields in the middle. The output still isn’t passed correctly to the Agent…would you mind sharing just a streamlined version of the nodes to get inspiration?
Appreciate the help a lot!!

Currently, I have this issue: the query is not passed to the agent properly:

Hi @Afamocc. The workflow I have to the shared pipeline is this simple one below. Hope that is what you need.



1 Like

Thanks! I don’t know why, but mine works only when the 1st webhook is set up to POST…I also see that you let openwebui send the message request for the chat title: does it works? Is the title applied to the chat in openwebui?
In my case I had to disable it.
Also, one major issue is that RAG citations are NOT reported into openwebui…that’s a major flaw of openwebui!! It’s unusable this way, unless there is a way around it…

Yes, the title is applied to the chat in Open WebUI in my case.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.