Skip to main content

JS Embed Guide

The JS embed is the platform-independent way to integrate Module7 into any website or CMS. It requires no server-side code — only a reverse proxy, a script tag, and an HTML element.

This guide explains the underlying mechanics and requirements. It is intentionally CMS-agnostic: the same steps apply whether you are using WordPress, a custom PHP application, a static site generator, or any other environment. For concrete step-by-step instructions for a specific platform, jump directly to the relevant guide:

No SEO support

With the JS embed, Module7 content is fetched and rendered in the browser after the page loads. Search engine crawlers that do not execute JavaScript will see an empty <m7-view> element — the content is not indexed.

If SEO is a requirement, a server-side adapter is the right approach instead.

Not suitable for all CMS platforms

The JS embed relies on a reverse proxy to handle URL routing for deep-linked views (e.g. /listing?city=Berlin, /detail/id=abc123). This works well in environments where you have full control over the web server configuration.

However, some CMS platforms manage URL routing internally and cannot delegate it to a reverse proxy. TYPO3 is a prime example: deep-link URLs must be handled through TYPO3's own routing enhancer, which is part of the CMS adapter — a plain reverse proxy cannot intercept and resolve those URLs correctly within TYPO3's routing lifecycle.

If you are unsure whether the JS embed is suitable for your platform, check the platform-specific guides or contact us.

CSS isolation

Module7 is designed so that its styles do not affect the host page, and the host page's styles do not affect Module7's output. In the vast majority of cases you can embed Module7 on any website without worrying about CSS conflicts in either direction.

In rare edge cases, inherited CSS properties or global resets on the host page may still have an influence. If you observe unexpected styling, browser developer tools can help identify where the style originates.


How the embed works

When <m7-view> is placed on a page, it immediately sends a POST request to the Module7 server. The server performs a full SSR render and returns the result as JSON. The element then injects the rendered HTML into its shadow DOM and mounts the client app for interactivity.

This means SSR happens per embed, on demand — not only on direct page loads. The browser never renders Module7 content from scratch; it always receives pre-rendered HTML from the server and hydrates it.

Page loads in browser
└─ loader.js executes
└─ registers <m7-view> as a custom element
└─ connectedCallback fires
└─ POST /<view-path>
Headers: Integration-Key, Accept: application/json
Body: { language, timeZone, ... }
└─ Server renders Vue app → returns { appHtml, cssProperties, dataBlocks, assets }
└─ Element injects HTML into shadow DOM
└─ Vue hydrates → interactive

What an integration requires

A complete integration has three parts:

PartRequiredPurpose
Reverse proxy for /module7/*YesServes the loader, JS bundles, and CSS assets from the Module7 server through the host domain
Loader script on every pageYesRegisters the <m7-view> custom element
<m7-view> element on view pagesYesTriggers the SSR render and displays content
Deep-link routingRecommendedAllows the CMS to serve Module7 view URLs as regular pages

Part 1: Reverse proxy

All /module7/* requests must be forwarded from the host domain to the Module7 server. This makes the loader and all JS/CSS assets appear to come from the same origin as the host website, which is required for the element to correctly derive its service URL at runtime.

The following paths must be proxied:

PathContent
/module7/loader.jsBootstrap script — loads the hashed embed bundle
/module7/entries/*Hashed embed and client JS bundles
/module7/assets/*CSS, fonts, images

Nginx example:

location ^~ /module7/ {
proxy_pass https://mo7.vns.services/module7/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header Accept-Encoding "";
}

Apache example:

ProxyPreserveHost On
ProxyPass /module7/ https://mo7.vns.services/module7/
ProxyPassReverse /module7/ https://mo7.vns.services/module7/

Part 2: Loading the loader script

The loader script must be included on every page of the host website. It registers the <m7-view> custom element. Without it, <m7-view> tags in the page markup are treated as unknown HTML and nothing renders.

Include it as a standard script tag:

<script src="/module7/loader.js"></script>

Place this tag in the <head> or at the end of <body>. The loader is cached by the browser for 6 hours (Cache-Control: public, max-age=21600), so there is no performance concern about including it on every page.

Automatic injection via Nginx:

If you want to avoid modifying page templates, Nginx can inject the script tag into every HTML response automatically:

sub_filter '</head>' '<script src="/module7/loader.js"></script></head>';
sub_filter_once on;

Both approaches are equivalent — use whichever fits your setup.


Part 3: Placing the <m7-view> element

Once the loader is active, place a <m7-view> element on any page where Module7 content should appear:

<m7-view
view="listing"
token="your-integration-key">
</m7-view>

The token attribute is always required. See the attribute reference for all available attributes.

Fallback for CMSes that strip custom elements

Some CMS environments sanitize HTML and remove unknown tags like <m7-view>. In these cases, use a standard <div> with data-m7-view and prefix all attributes with data-:

<div
data-m7-view
data-view="listing"
data-token="your-integration-key">
</div>

The loader automatically detects and upgrades these placeholders to proper <m7-view> elements on page load. All attributes work identically.


By default, <m7-view> uses window.location.pathname to determine which view to render — unless the view attribute explicitly sets one. This enables URL-driven navigation: when a user shares or bookmarks a filtered URL like /listing?city=Heidelberg, the same view state is restored on load.

For this to work, the CMS must serve a page at every URL that Module7 can navigate to. Specifically:

URL patternMust be handled by
/listing and /listing?...A CMS page with <m7-view token="..."> (no view attribute)
/detail/*A CMS page with <m7-view token="..."> (no view attribute)

When Module7 navigates client-side (e.g. from listing to detail), it updates window.location using the History API. If the user then refreshes the page, the CMS must serve its page at that URL — otherwise a 404 is returned.

tip

If you use the view attribute to hard-code the view, Module7 ignores the URL path and deep-link routing is not needed. This is simpler to set up but means URLs do not reflect view state.

The X-Original-URL header

If your reverse proxy rewrites the request path before forwarding the SSR POST to the Module7 server, the server may reconstruct the wrong internal URL. In that case, set the X-Original-URL header to the full original public URL so the server can route correctly:

proxy_set_header X-Original-URL $scheme://$host$request_uri;

Verifying the integration

Once everything is in place, open your browser's developer tools and check:

  1. Network tab — you should see a POST request to /listing (or whichever view) returning a JSON response with appHtml.
  2. Elements tab<m7-view> should have a shadow root containing the rendered HTML.
  3. Console — any configuration errors (missing token, invalid filter, unknown view) are shown as styled error messages inside the element and as logger.error calls in the console.