Frontend content delivery witn n8n

Hi community!

For a long time, n8n didn’t have any frontend features for third-party users. This has changed over the last months with the Form Trigger and Chat Trigger nodes. Also, a dedicated HTML node is available, but more on that later.

Let’s discuss how to deliver frontend pages to users in a more universal way.

This topic is a bit in-depth, but I promise you’ll see some nice screenshots from the ongoing projects

Why frontend for external users?

n8n excels at automations, especially when connecting multiple “backend” services (databases, code execution, under-the-hood logic).

However, there are 3 specific cases when users need custom HTML pages:

  • To present complex data
  • To manipulate data with visuals/charts
  • To input data back into systems (i.e. human-in-the-loop for AI tasks)

When connecting purely backend services, there’s no built-in way to deliver custom HTML. And developing a standalone user-facing app is often overkill.

Here’s how I deliver interactive HTML pages with n8n

Already published:

  1. n8n workflow dashboard

    • Serves pure XML + XSLT template
    • Browser handles all rendering
    • Uses native browser XML templating (W3C standard)
  2. Workflow visualizer dashboard

    • HTML page with Mermaid.js integration
    • JSON data delivery
    • AJAX for individual chart requests

UPD: already published
Work in progress:
3. n8n workflow auto documentation with Docsify

  • Integrates docsify.js within HTML pages
  • Serves markdown text segments
  • Supports auto-generated documentation
  • Allows for live documentation editing with markdown preview

Main page features all workflows with links to docs

New workflow documentation starts from a template + a Mermaid chart

New doc pages are generated automatically

Work in progress:
4. If the previous example wasn’t exciting enough, here’s another use-case. Take a no-code database, NocoDB is a cool project. They recently introduced a Button column; it can make HTTP Requests. And guess what? You can call n8n webhooks that serve HTML pages with some elements from the database. I’ve built an editor (powered by Konva.js) that connects with FLUX.1 inpainting API. Here’s how it works :point_down:

select data and press the button

Work on one of the image from this DB record

Edited images are uploaded back to the DB automatically

This enables both seamless image editing and further automated inpainting: combine single image mask with multiple prompts and get multiple variations of the same product.

Cool? Yeah, but here’s a catch

I’ve tried these approaches and found several limitations:

  • Writing and debugging code is challenging
  • Serving complete HTML pages with a single node is cumbersome
  • Poor separation of HTML content and CSS styling
  • Adding dynamic data is complicated

Is there a universal way for delivering interactive content?

I’m not sure. Maybe I’m not going in the right direction at all.

The easiest template for page delivery I know looks like this:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Some Cool Lib Demo</title>
    
    <!-- CSS for some-cool-lib -->
    <link rel="stylesheet" href="https://cdn.example.com/some-cool-lib/v1.0/some-cool-lib.css">
    
    <!-- JavaScript for some-cool-lib -->
    <script src="https://cdn.example.com/some-cool-lib/v1.0/some-cool-lib.js"></script>
</head>
<body>
    <div id="cool-lib-container">
        <script>
            const coolLibConfig = {
                settings: {
                    theme: "{{ $json.theme }}",
                    language: "{{ $json.language }}",
                },
                data: {
                    items: {{ $json.items }},
                    maxResults: {{ $json.maxResults }},
                    filters: {
                        category: "{{ $json.filterCategory }}",
                        dateRange: {
                            start: "{{ $json.startDate }}",
                            end: "{{ $json.endDate }}"
                        }
                    }
                }
            };

            // Initialize some-cool-lib with config
            SomeCoolLib.init('#cool-lib-container', coolLibConfig);
        </script>
    </div>
</body>
</html>

You can basically abstract all functionality behind a JS file and serve a simple HTML page with some {{JS expessions}} to put the data.

What do you think? How would you tackle this? Let’s discuss!
Also, feel free to connect with me on LinkedIn.

8 Likes

Awesome, amazing works, I’m thinking about how can I handle the front end (for the moment i have thought to plasmic).

But just yesterday i had thought “how can I handle front end in n8n itself, it is possible!?”

And thanks to you, it seems possible.

How do you think you can use an entire library without CDN?

1 Like

Thanks a lot for your feedback!

How … you can use an entire library without CDN

Not sure I got the question. You can keep the JS files anywhere (in S3 buckets?), once users call the webhook, the JS lib is served either from the original developers’ source, or the users can copy-paste the custom library to their resources.

Yes of course we can host on our s3…but i mean can we found a way to use js library like install via npm on a server?

Because use of external link can cause delay or issue if the connection between not work good

I’ve done something similar (by beating ChatGPT into submission).

Data is stored in NocoDB.
HTML file includes a target <div>
JS functions dynamically read the data and update the target <div>.
I interact with n8n via webhooks.

Everything is in a simple html file served by an NGINX container.

I’m a big fan of the abstracted html.

1 Like