Skip to main content
The html operation renders HTML templates using template engines. It’s typically used in ensemble flows when an HTTP trigger needs to return server-rendered HTML. Note: The html operation is for rendering only. HTTP routing, authentication, CORS, and middleware are configured in the trigger: section using type: http.

HTTP Middleware

When using the html operation with HTTP triggers, you can add Hono middleware for cross-cutting concerns like logging, compression, and security headers:
name: blog-post
trigger:
  - type: http
    path: /blog/:slug
    methods: [GET]
    public: true

    # Add middleware for performance and security
    middleware:
      - logger          # Log requests
      - compress        # Gzip compression
      - secure-headers  # Security headers
      - etag            # Cache validation

    responses:
      html: {enabled: true}

agents:
  - name: render-page
    operation: html
    config:
      template: |
        <article>
          <h1>{{ title }}</h1>
          <div>{{ content }}</div>
        </article>
Middleware executes before the HTML rendering, allowing you to add:
  • Request/response logging (logger)
  • Response compression for faster page loads (compress)
  • Security headers (secure-headers)
  • Cache validation with ETags (etag)
  • Custom authentication and rate limiting
See the HTTP Middleware Guide for complete documentation on using middleware with HTML responses.

Usage in Ensembles with HTTP Trigger

name: blog-post
trigger:
  - type: http
    path: /blog/:slug
    methods: [GET]
    public: true
    responses:
      html: {enabled: true}
    templateEngine: liquid

flow:
  # Fetch data
  - agent: fetch-post
    input: {slug: ${input.params.slug}}

  # Render HTML
  - operation: html
    config:
      template: |
        <article>
          <h1>{{ fetch-post.title }}</h1>
          <div>{{ fetch-post.content }}</div>
        </article>
      data: ${fetch-post}

Configuration

operation: html
config:
  template: string    # HTML template with variables
  data: object       # Data to render in template
  engine: string     # Template engine (liquid, handlebars, simple)

Template Engines

Liquid (Default)

operation: html
config:
  template: |
    <h1>{{ title }}</h1>
    {% for item in items %}
      <p>{{ item.name }}</p>
    {% endfor %}
  data: ${previous-step.output}

Handlebars

operation: html
config:
  template: |
    <h1>{{title}}</h1>
    {{#each items}}
      <p>{{name}}</p>
    {{/each}}
  data: ${previous-step.output}
  engine: handlebars

Simple (String Interpolation)

operation: html
config:
  template: |
    <h1>{{title}}</h1>
    <p>{{description}}</p>
  data: ${previous-step.output}
  engine: simple

Complete Example

name: user-dashboard
trigger:
  - type: http
    path: /dashboard/:userId
    methods: [GET]
    auth:
      type: bearer
      secret: ${env.API_KEY}
    responses:
      html: {enabled: true}
    templateEngine: liquid

flow:
  # Step 1: Fetch user data
  - agent: get-user
    input: {userId: ${input.params.userId}}

  # Step 2: Fetch user stats
  - agent: get-user-stats
    input: {userId: ${input.params.userId}}

  # Step 3: Render HTML dashboard
  - operation: html
    config:
      template: |
        <!DOCTYPE html>
        <html>
        <head>
          <title>Dashboard - {{ get-user.name }}</title>
        </head>
        <body>
          <h1>Welcome, {{ get-user.name }}</h1>
          <div class="stats">
            <p>Total Orders: {{ get-user-stats.orders }}</p>
            <p>Revenue: ${{ get-user-stats.revenue }}</p>
          </div>
        </body>
        </html>
      data:
        get-user: ${get-user}
        get-user-stats: ${get-user-stats}

Personalization with Cookies

Use cookies to personalize HTML content based on user preferences or session data:
name: personalized-page
trigger:
  - type: http
    path: /home
    methods: [GET]
    public: true
    responses:
      html: {enabled: true}

agents:
  # Check for preference cookie
  - name: get-theme
    operation: cookies
    config:
      action: get
      name: theme_preference

  # Load user session if logged in
  - name: get-session
    condition: ${input.cookies.session_id}
    operation: storage
    config:
      type: kv
      action: get
      key: session-${input.cookies.session_id}

  # Render personalized page
  - name: render
    operation: html
    config:
      template: |
        <!DOCTYPE html>
        <html data-theme="{{ theme }}">
        <head>
          <title>{% if user %}Welcome back, {{ user.name }}{% else %}Welcome{% endif %}</title>
        </head>
        <body>
          {% if user %}
            <p>Last visit: {{ user.lastVisit }}</p>
          {% else %}
            <p>Create an account for a personalized experience</p>
          {% endif %}
        </body>
        </html>
      data:
        theme: ${get-theme.output.value || 'light'}
        user: ${get-session.output.value}
Set preference cookies when users change settings:
agents:
  - name: save-theme
    operation: cookies
    config:
      action: set
      name: theme_preference
      value: ${input.body.theme}
      maxAge: 31536000  # 1 year
      purpose: personalization

Next Steps