> ## Documentation Index
> Fetch the complete documentation index at: https://developers.kit.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Dynamic content blocks plugin flow

> Step-by-step guide to building a dynamic content block integration

Let's say you're building an abandoned cart recovery integration. Subscribers who leave items in their cart are enrolled in a Visual Automation that sends them an email containing a personalized block showing exactly what they left behind. Here's the full flow:

<Steps>
  <Step title="Build your automation event plugin">
    You create an [automation node plugin](/plugins/automation-nodes/overview) that fires when a subscriber abandons their cart. This event plugin is responsible for capturing the subscriber's cart data and returning it on each event in the `context` field of your `fetch_events` response. Kit stores this per-subscriber context and exposes it in Liquid under a path like `automation.yourapp.<event_node_identifier>.*`, where `<event_node_identifier>` is the **`identifier` on that event node** (not the dynamic content block's identifier).

    You also configure the event's **Sample data** JSON on the event plugin form. The top-level keys define the fields creators can reference in Liquid, and the nested values are used to render previews in the email editor. See [automation node plugin configuration](/plugins/automation-nodes/plugin-configuration#event-context).
  </Step>

  <Step title="Create the content block endpoint">
    You create a POST endpoint on your server that generates the Liquid-templated HTML for your content block. This endpoint receives the creator's settings choices and returns HTML containing Liquid variables—for example, `{{ automation.yourapp.abandoned_checkout.checkout_url }}` when the linked event node's `identifier` is `abandoned_checkout`.

    *Details on configuring this endpoint and the expected request/response format are in [plugin configuration](/plugins/content-blocks/dynamic-blocks/plugin-configuration).*
  </Step>

  <Step title="Optionally create a search endpoint">
    If your block's sidebar includes a [search input](/plugins/component-library/search-input) to let creators browse or select data from your service (for example, choosing a fallback product to display), create a POST endpoint to serve those results.
  </Step>

  <Step title="Create and publish your app">
    You [create your app in Kit](https://app.kit.com/apps?is=created) and configure both the automation event plugin and the dynamic content block plugin. On the event plugin, paste **Sample data** JSON into the Context card. On the content block plugin, set `dynamic` to `true` and link it to your event plugin using `related_plugin_id`—the read-only sample-data preview will appear automatically.

    Once both plugins are ready, submit your app for approval and publish.
  </Step>

  <Step title="Creator installs your app">
    A Kit user installs your app, triggering your plugin's [OAuth authorization](/plugins/oauth-authorization) flow.
  </Step>

  <Step title="Creator builds a Visual Automation using your event plugin">
    The creator sets up a Visual Automation workflow that includes your automation event plugin (e.g., "Abandoned Cart"). When a subscriber triggers this event, Kit captures the data your plugin provides and stores it in the automation context for that subscriber.
  </Step>

  <Step title="Creator adds your content block to the automation email">
    Inside the Visual Automation, the creator edits the sequence email and adds your dynamic content block from the element menu. Upon adding it—and each time they adjust a setting—Kit makes a POST request to your content block endpoint with the creator's settings.
  </Step>

  <Step title="Return Liquid-templated HTML">
    Your server responds with HTML containing Liquid variables that reference the automation context—for example:

    ```html theme={null}
    {% if automation.yourapp.abandoned_checkout %}
      {% for product in automation.yourapp.abandoned_checkout.products limit: 4 %}
        <table>
          <tr><td>{{ product.name }}</td></tr>
          <tr><td>{{ product.price }}</td></tr>
        </table>
      {% endfor %}
      <a href="{{ automation.yourapp.abandoned_checkout.checkout_url }}">Complete your order</a>
    {% endif %}
    ```

    Kit renders this template with your `default_values` to generate a preview for the creator to see in the editor.
  </Step>

  <Step title="Kit personalizes and sends the email">
    When the automation sends the email to a subscriber, Kit renders the stored Liquid template using that subscriber's actual automation data—filling in their real cart contents, checkout URL, and totals. Each subscriber receives a personalized version of the block.
  </Step>
</Steps>
