Skip to content

enhancely/enhancely-js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Enhancely — GTM / CMS-less JS

If you can’t (or don’t want to) change your backend templates, this integration lets you add Enhancely JSON‑LD using:

  • one JS snippet you paste into GTM (or <head>)
  • one small proxy endpoint on your domain (keeps your Enhancely API key secret)

Before you start (must read)

  • Never put ENHANCELY_API_KEY in GTM or client-side code.
    GTM runs in the browser. Anything in it is public.
  • You must host a proxy endpoint on your domain:
    • POST https://YOUR_DOMAIN/_enhancely/jsonld
  • Production security: configure ALLOWED_HOSTS on your proxy/worker to prevent abuse.

What’s in this folder

  • Client snippet: enhancely-js.js
  • Proxy templates:
    • Cloudflare Worker: proxy/cloudflare/worker.mjs
    • Node (dockerized): proxy/node/server.js
  • Example pages:
    • Local demo: example/index.html (edit proxyUrl)
    • Same-domain server demo: example/server.html (uses /_enhancely/jsonld)
    • “Processing” demo: example/processing.html (exercises 201/202 retry flow)

Quick “do this” checklist (most customers)

  1. Deploy the proxy
  • Use Cloudflare Worker or your own server (Node/PHP/etc.)
  • Set ENHANCELY_API_KEY server-side
  • Restrict allowed hosts (recommended)
  1. Paste the snippet
  • GTM Custom HTML tag (recommended) or site <head>
  • Set proxyUrl
  1. Verify
  • Proxy returns JSON‑LD + ETag
  • Page has exactly one JSON‑LD <script> in <head>
  • Reload shows 304/412 behavior (ETag revalidation)

Step-by-step

1) Deploy the proxy (required)

You need:

  • Endpoint: POST /_enhancely/jsonld
  • Request body: { "url": "https://yourdomain.com/some/page" }
  • Optional header: If-None-Match: <etag> (no quotes)

The proxy must:

  • Keep ENHANCELY_API_KEY server-side
  • Call Enhancely: POST https://app.enhancely.ai/api/v1/jsonld
  • Forward If-None-Match
  • Return:
    • 200 with JSON { status, etag, jsonld } when ready
    • 304 or 412 (empty body) when not modified

Option A: Cloudflare Worker (fastest)

Deploy proxy/cloudflare/worker.mjs.

Env vars:

ENHANCELY_API_KEY=...
ENHANCELY_API_URL=https://app.enhancely.ai/api/v1
ALLOWED_HOSTS=example.com,www.example.com

Route it so it serves /_enhancely/jsonld on the same domain as your site.

Minimal Worker deploy (example):

  • Create a Worker and set a route for https://YOUR_DOMAIN/_enhancely/jsonld*
  • Set secrets/vars:
    • ENHANCELY_API_KEY as a secret
    • ENHANCELY_API_URL as a variable (optional)
    • ALLOWED_HOSTS as a variable (recommended)

See proxy/cloudflare/README.md for a wrangler-based deploy walkthrough.

Option B: Node proxy on your server (docker)

Use the provided Node Dockerfile:

  • proxy/node/Dockerfile

You can run it with any Docker platform, behind your existing reverse proxy (recommended for same-domain routing).

Hetzner VPS note (common setup):

  • Run the container on the server (e.g. 127.0.0.1:8787)
  • In your web server (nginx/Caddy/Apache), route /_enhancely/jsonld to that local port so the public URL stays same-domain:
    • nginx:
location = /_enhancely/jsonld {
  proxy_pass http://127.0.0.1:8787/_enhancely/jsonld;
}

If you can’t add a route, you can still use a port URL as proxyUrl (less ideal):
proxyUrl: "https://YOUR_DOMAIN:8787/_enhancely/jsonld"

Env example:

  • proxy/node/.env.example

Important: if you deploy via rsync, exclude .env:

rsync -av --delete --exclude '.env' --exclude '.DS_Store' enhancely-js/ YOUR_SERVER:/path/to/enhancely-js/

Node Docker quickstart:

# build
docker build -t enhancely-jsonld-proxy ./proxy/node

# run (create your own ./proxy/node/.env first)
docker run --rm -p 8787:8787 --env-file ./proxy/node/.env enhancely-jsonld-proxy

Notes:

  • Node runtime: the container uses Node 20 (fetch is built-in).
  • Security: set ALLOWED_HOSTS for production. For legacy behavior without ALLOWED_HOSTS, you can set ALLOW_SAME_HOST_FALLBACK=1 (not recommended).

2) Paste the client snippet (GTM or <head>)

GTM (recommended)

Create a Custom HTML tag and paste:

<script>
window.EnhancelyJsonldConfig = {
  proxyUrl: "https://YOUR_DOMAIN/_enhancely/jsonld",
  // Optional:
  // debug: true,
  // observeSpa: true,
  // If your site differentiates pages/sites via query params (e.g. ?lang=de or ?site=foo),
  // list them here so the correct schema is fetched per variant:
  // includeQueryParams: ["lang", "site"],
};
</script>
<script>
/* Paste the contents of enhancely-js.js here */
</script>

Direct <head>

Paste the same config + snippet as early as possible in <head>.

3) Verify it’s working (copy/paste checks)

A) Proxy works

curl -sS -i -X POST 'https://YOUR_DOMAIN/_enhancely/jsonld' \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://YOUR_DOMAIN/some/page"}' | head -n 25

Expected:

  • HTTP 200
  • JSON includes status: 200, etag, and jsonld with @context

B) ETag revalidation works (304/412)

Copy the returned etag (it should have no quotes) and re-run:

curl -sS -i -X POST 'https://YOUR_DOMAIN/_enhancely/jsonld' \
  -H 'Content-Type: application/json' \
  -H 'If-None-Match: PASTE_ETAG_HERE' \
  -d '{"url":"https://YOUR_DOMAIN/some/page"}' | head -n 25

Expected:

  • HTTP 304 or HTTP 412
  • empty body

C) Page injects JSON‑LD

Open your page and confirm <head> contains exactly one:

  • <script type="application/ld+json" id="enhancely-jsonld">

If debug: true, you’ll also see [enhancely] logs in the console.

Client configuration (all options)

Set via window.EnhancelyJsonldConfig before loading/pasting enhancely-js.js:

  • proxyUrl (string, required): Proxy endpoint URL (recommended same-domain), e.g. "/_enhancely/jsonld" or "https://example.com/_enhancely/jsonld".
  • scriptId (string, default enhancely-jsonld): The injected <script> element id.
  • storage (localStorage | sessionStorage | none, default localStorage): Where to cache {etag,jsonld,ts}.
  • cachePrefix (string, default enhancely:jsonld:): Storage key prefix.
  • revalidateAfterMs (number, default 300000): Cache freshness window. Fresh cache injects without a network call.
  • timeoutMs (number, default 4000): Network timeout for the proxy request.
  • debug (boolean, default false): Logs "[enhancely]" debug lines.
  • includeQueryParams (string[], default []): Query params to keep in the canonical URL identity. All other query params are stripped.
  • observeSpa (boolean, default false): Re-run on SPA navigation (pushState/replaceState/popstate).
  • processingRetries (number, default 4): Retry count when status is 201/202.
  • processingRetryDelayMs (number, default 4000): Delay between retries.

How the caching behaves (so you know what to expect)

  • Cache is stored in browser storage (default localStorage) per canonical URL.
  • On first ready fetch, it caches { etag, jsonld, ts }.
  • On later loads:
    • if cache is “fresh” (default 5 minutes), it injects immediately with no network call
    • if cache is “stale”, it revalidates with If-None-Match
    • on 304/412, it keeps the cached JSON‑LD

“Processing” (201/202) behavior

Sometimes Enhancely needs time to crawl a fresh URL and returns 201/202 first.

This snippet:

  • does not inject the 201/202 “problem” payload
  • retries a few times (configurable) and only injects once real JSON‑LD is ready (status: 200 and has @context)

Troubleshooting (fast)

  • Proxy returns 500 Missing ENHANCELY_API_KEY

    • Your server env isn’t set (or the container wasn’t recreated after changing .env)
    • If using Docker: recreate/restart the proxy container after changing env vars
  • Proxy returns 500 Missing ALLOWED_HOSTS

    • Set ALLOWED_HOSTS=example.com,www.example.com on the proxy/worker (recommended for production)
    • For local dev, use localhost or explicitly set ALLOW_SAME_HOST_FALLBACK=1 (not recommended)
  • Proxy returns 403 URL host not allowed

    • Add your domain to ALLOWED_HOSTS (or you’re testing a different host than your site)
  • No <script id="enhancely-jsonld"> appears

    • Confirm proxyUrl is correct and reachable
    • Turn on debug: true and check console logs
    • If your site is an SPA, enable observeSpa: true
  • SEO tooling doesn’t see the JSON‑LD

    • Client-injected JSON‑LD can be less reliable than SSR. Validate with Google Rich Results Test and Search Console.

Security notes (recommended)

  • Keep the proxy same-domain when possible (avoid CORS complexity).
  • Configure ALLOWED_HOSTS to prevent the endpoint being used to generate JSON-LD for arbitrary domains.
  • Add basic rate limiting at your edge / reverse proxy (especially for public endpoints).

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors