Astro · multi-site
Standard way to install KeyBlogging Comments on Astro (and similar) sites. Use this page as the source of truth for site agents — so every property gets the same site-wide login behavior.
Admin tutorial Dashboard Agent API Home
Current embed cache-bust version: v=6
When KeyBlogging ships embed.js fixes, bump your site’s
KEYBLOGGING_EMBED_VERSION (or equivalent) to match.
One GFAVIP login covers the whole site (same origin), not each post page.
| Piece | Role |
|---|---|
| Login popup | User signs in on https://my.keyblogging.com → popup postMessages a token to the blog |
| Blog storage | Token saved on the blog origin in localStorage, sessionStorage, and cookie Path=/ |
| embed.js | Reads that storage on every post page; posts comments with Authorization: Bearer … |
| Auth bridge | Layout-level listener so login is stored even if embed.js loads late or popup closes fast |
Do not expect login to work across www.example.com and example.com — different origins, different storage.
Pick one canonical host and redirect the other.
slug (e.g. miksblogdesign)mikesblogdesign.com (no https://)coffee, calendar2026)On every article/page that should show comments:
<!-- data-* lets embed.js re-bind after Astro soft navigation -->
<div
id="keyblogging-comments"
data-blog="YOUR-BLOG-SLUG"
data-post="YOUR-POST-SLUG"
></div>
<script
src="https://my.keyblogging.com/static/embed.js?blog=YOUR-BLOG-SLUG&post=YOUR-POST-SLUG&v=6"
async
></script>
Example (mikesblogdesign):
<div id="keyblogging-comments" data-blog="miksblogdesign" data-post="coffee"></div>
<script
src="https://my.keyblogging.com/static/embed.js?blog=miksblogdesign&post=coffee&v=6"
async
></script>
// src/utils/keyblogging.ts
export const KEYBLOGGING_APP = "https://my.keyblogging.com";
export const KEYBLOGGING_BLOG_SLUG = "your-blog-slug";
/** Bump when KeyBlogging ships embed.js updates */
export const KEYBLOGGING_EMBED_VERSION = "6";
export function keybloggingEmbedSrc(postSlug: string) {
const q = new URLSearchParams({
blog: KEYBLOGGING_BLOG_SLUG,
post: postSlug,
v: KEYBLOGGING_EMBED_VERSION,
});
return `${KEYBLOGGING_APP}/static/embed.js?${q}`;
}
Browsers cache embed.js aggressively. Always pass &v=….
When KeyBlogging releases embed fixes, bump KEYBLOGGING_EMBED_VERSION on every Astro site
(or set it from an env var shared across repos).
Current recommended value: 6
Load once in the root layout (every page — not only posts with comments).
This catches postMessage from the login popup and writes site-wide storage.
KeybloggingAuthBridge.astro---
// Include in BaseLayout / every layout that wraps pages
const APP = "https://my.keyblogging.com";
---
<script is:inline define:vars=>
(function () {
var TOKEN = "keyblogging_embed_token";
var USER = "keyblogging_embed_user";
var DAYS = 180;
function cookieSet(name, val) {
if (!val) {
document.cookie = name + "=; Path=/; Max-Age=0; SameSite=Lax";
return;
}
document.cookie =
name + "=" + encodeURIComponent(val) +
"; Path=/; Max-Age=" + (DAYS * 86400) + "; SameSite=Lax";
}
function persist(token, username) {
try {
if (token) {
localStorage.setItem(TOKEN, token);
sessionStorage.setItem(TOKEN, token);
cookieSet(TOKEN, token);
if (username) {
localStorage.setItem(USER, username);
sessionStorage.setItem(USER, username);
cookieSet(USER, username);
}
} else {
localStorage.removeItem(TOKEN);
sessionStorage.removeItem(TOKEN);
localStorage.removeItem(USER);
sessionStorage.removeItem(USER);
cookieSet(TOKEN, null);
cookieSet(USER, null);
}
} catch (e) {}
try {
var bc = new BroadcastChannel("keyblogging-auth");
bc.postMessage({ type: "keyblogging-auth", token: token || null, username: username || null });
bc.close();
} catch (e) {}
}
function accept(data, origin) {
if (!data || data.type !== "keyblogging-auth" || !data.token) return;
try {
if (origin && new URL(origin).hostname !== new URL(APP).hostname) return;
} catch (e) { return; }
persist(data.token, data.username || null);
}
window.addEventListener("message", function (ev) {
accept(ev.data, ev.origin);
});
})();
</script>
Include the bridge in both (or all) layouts so marketing pages and posts share the same auth listener.
Redirect www + http → one HTTPS apex (or one www — pick one).
netlify.toml example[[redirects]]
from = "http://www.example.com/*"
to = "https://example.com/:splat"
status = 301
force = true
[[redirects]]
from = "https://www.example.com/*"
to = "https://example.com/:splat"
status = 301
force = true
[[redirects]]
from = "http://example.com/*"
to = "https://example.com/:splat"
status = 301
force = true
data-blog and data-post on #keyblogging-commentsastro:page-load and re-hydrates auth + reloads the thread#keyblogging-comments {
--kb-fg: inherit;
--kb-muted: #6b7280;
--kb-border: #e5e7eb;
--kb-bg: transparent;
--kb-accent: #111;
--kb-radius: 8px;
--kb-font: inherit;
}
Site-specific look = Astro/site CSS. Embed behavior & defaults = KeyBlogging.
Implement
KEYBLOGGING_EMBED_VERSION = "6" (or current)blog, post, v, and data-*Test
keyblogging_embed_token in localStorage and Cookies on apex domain| Symptom | Fix |
|---|---|
| Login works then gone on next page | Auth bridge missing; or www vs non-www; or old embed without v= |
| Token only on my.keyblogging.com storage | Expected in the popup. Blog must get token via postMessage → bridge/embed |
| CORS / post fails with origin error | Dashboard blog domain must match host (e.g. mikesblogdesign.com) |
| Stale embed bugs | Bump v= / KEYBLOGGING_EMBED_VERSION |
| Need to re-login every ~6 months | Embed token TTL (default 180 days). Re-login once. |
For AI site agents — paste this goal:
Integrate KeyBlogging Comments per https://my.keyblogging.com/docs/astro
- Blog slug: <SLUG>
- Domain: <apex host>
- Embed version: 6
- Include KeybloggingAuthBridge in layouts
- Canonical www/http → https://apex
- data-blog / data-post on comments div
- Cache-bust embed.js with v=6