mirror of
https://github.com/koala73/worldmonitor.git
synced 2026-04-25 17:14:57 +02:00
feat(seo): BlogPosting schema, FAQPage JSON-LD, extensible author system (#2284)
* feat(seo): BlogPosting schema, FAQPage JSON-LD, author system, AI crawler welcome Blog structured data: - Change @type Article to BlogPosting for all blog posts - Author: Organization to Person with extensible default (Elie Habib) - Add per-post author/authorUrl/authorBio/modifiedDate frontmatter fields - Auto-extract FAQPage JSON-LD from FAQ sections in all 17 posts - Show Updated date when modifiedDate differs from pubDate - Add author bio section with GitHub avatar and fallback Main app: - Add commodity variant to middleware VARIANT_HOST_MAP and VARIANT_OG - Add commodity.worldmonitor.app to sitemap.xml - Shorten index.html meta description to 136 chars (was 161) - Remove worksFor block from index.html author JSON-LD - Welcome all bots in robots.txt (removed per-bot blocks, global allows) - Update llms.txt: five variants listed, all 17 blog post URLs added * fix(seo): scope FAQ regex to section boundary, use author-aware avatar - extractFaqLd now slices only to the next ## heading (was: to end of body) preventing bold text in post-FAQ sections from being mistakenly extracted - Avatar src now derived from DEFAULT_AUTHOR_GITHUB constant (koala73) only when using the default author; custom authors fall back to favicon so multi-author posts show a correct image instead of the wrong profile
This commit is contained in:
@@ -10,6 +10,10 @@ const blog = defineCollection({
|
|||||||
keywords: z.string(),
|
keywords: z.string(),
|
||||||
audience: z.string(),
|
audience: z.string(),
|
||||||
pubDate: z.coerce.date(),
|
pubDate: z.coerce.date(),
|
||||||
|
modifiedDate: z.coerce.date().optional(),
|
||||||
|
author: z.string().optional(),
|
||||||
|
authorUrl: z.string().url().optional(),
|
||||||
|
authorBio: z.string().optional(),
|
||||||
heroImage: z.string().optional(),
|
heroImage: z.string().optional(),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,9 +12,10 @@ interface Props {
|
|||||||
section?: string;
|
section?: string;
|
||||||
jsonLd?: Record<string, unknown>;
|
jsonLd?: Record<string, unknown>;
|
||||||
breadcrumbLd?: Record<string, unknown>;
|
breadcrumbLd?: Record<string, unknown>;
|
||||||
|
faqLd?: Record<string, unknown>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { title, description, metaTitle, keywords, ogType, ogImage, publishedTime, modifiedTime, author, section, jsonLd, breadcrumbLd } = Astro.props;
|
const { title, description, metaTitle, keywords, ogType, ogImage, publishedTime, modifiedTime, author, section, jsonLd, breadcrumbLd, faqLd } = Astro.props;
|
||||||
const pageTitle = metaTitle || title;
|
const pageTitle = metaTitle || title;
|
||||||
const resolvedOgImage = ogImage || 'https://www.worldmonitor.app/favico/og-image.png';
|
const resolvedOgImage = ogImage || 'https://www.worldmonitor.app/favico/og-image.png';
|
||||||
const resolvedOgType = ogType || 'website';
|
const resolvedOgType = ogType || 'website';
|
||||||
@@ -68,6 +69,9 @@ const keywordTags = keywords ? keywords.split(',').map(k => k.trim()).slice(0, 6
|
|||||||
{breadcrumbLd && (
|
{breadcrumbLd && (
|
||||||
<script type="application/ld+json" set:html={JSON.stringify(breadcrumbLd)} />
|
<script type="application/ld+json" set:html={JSON.stringify(breadcrumbLd)} />
|
||||||
)}
|
)}
|
||||||
|
{faqLd && (
|
||||||
|
<script type="application/ld+json" set:html={JSON.stringify(faqLd)} />
|
||||||
|
)}
|
||||||
|
|
||||||
<style is:global>
|
<style is:global>
|
||||||
@import '../styles/global.css';
|
@import '../styles/global.css';
|
||||||
|
|||||||
@@ -7,12 +7,17 @@ interface Props {
|
|||||||
metaTitle?: string;
|
metaTitle?: string;
|
||||||
keywords?: string;
|
keywords?: string;
|
||||||
pubDate: Date;
|
pubDate: Date;
|
||||||
|
modifiedDate?: Date;
|
||||||
|
author?: string;
|
||||||
|
authorUrl?: string;
|
||||||
|
authorBio?: string;
|
||||||
audience?: string;
|
audience?: string;
|
||||||
heroImage?: string;
|
heroImage?: string;
|
||||||
slug?: string;
|
slug?: string;
|
||||||
|
rawBody?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { title, description, metaTitle, keywords, pubDate, audience, heroImage, slug } = Astro.props;
|
const { title, description, metaTitle, keywords, pubDate, modifiedDate, author, authorUrl, authorBio, audience, heroImage, slug, rawBody } = Astro.props;
|
||||||
const ogImage = heroImage || (slug ? `https://www.worldmonitor.app/blog/images/blog/${slug}.jpg` : undefined);
|
const ogImage = heroImage || (slug ? `https://www.worldmonitor.app/blog/images/blog/${slug}.jpg` : undefined);
|
||||||
const formattedDate = pubDate.toLocaleDateString('en-US', {
|
const formattedDate = pubDate.toLocaleDateString('en-US', {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
@@ -20,6 +25,19 @@ const formattedDate = pubDate.toLocaleDateString('en-US', {
|
|||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
});
|
});
|
||||||
const isoDate = pubDate.toISOString();
|
const isoDate = pubDate.toISOString();
|
||||||
|
const isoModifiedDate = modifiedDate ? modifiedDate.toISOString() : isoDate;
|
||||||
|
const DEFAULT_AUTHOR = 'Elie Habib';
|
||||||
|
const DEFAULT_AUTHOR_URL = 'https://x.com/eliehabib';
|
||||||
|
const DEFAULT_AUTHOR_BIO = 'Founder of World Monitor. Previously co-founder & CEO of Anghami (NASDAQ: ANGH). Building open-source global intelligence infrastructure.';
|
||||||
|
const DEFAULT_AUTHOR_GITHUB = 'koala73';
|
||||||
|
const authorName = author || DEFAULT_AUTHOR;
|
||||||
|
const resolvedAuthorUrl = authorUrl || (authorName === DEFAULT_AUTHOR ? DEFAULT_AUTHOR_URL : undefined);
|
||||||
|
const resolvedAuthorBio = authorBio || (authorName === DEFAULT_AUTHOR ? DEFAULT_AUTHOR_BIO : undefined);
|
||||||
|
const avatarSrc = authorName === DEFAULT_AUTHOR
|
||||||
|
? `https://unavatar.io/github/${DEFAULT_AUTHOR_GITHUB}`
|
||||||
|
: '/favico/apple-touch-icon.png';
|
||||||
|
const showUpdated = modifiedDate && modifiedDate.getTime() !== pubDate.getTime();
|
||||||
|
const formattedModifiedDate = modifiedDate ? modifiedDate.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' }) : '';
|
||||||
|
|
||||||
const breadcrumbLd = {
|
const breadcrumbLd = {
|
||||||
"@context": "https://schema.org",
|
"@context": "https://schema.org",
|
||||||
@@ -41,19 +59,15 @@ const breadcrumbLd = {
|
|||||||
|
|
||||||
const jsonLd = {
|
const jsonLd = {
|
||||||
"@context": "https://schema.org",
|
"@context": "https://schema.org",
|
||||||
"@type": "Article",
|
"@type": "BlogPosting",
|
||||||
"headline": metaTitle || title,
|
"headline": metaTitle || title,
|
||||||
"description": description,
|
"description": description,
|
||||||
"datePublished": isoDate,
|
"datePublished": isoDate,
|
||||||
"dateModified": isoDate,
|
"dateModified": isoModifiedDate,
|
||||||
"author": {
|
"author": {
|
||||||
"@type": "Organization",
|
"@type": "Person",
|
||||||
"name": "World Monitor",
|
"name": authorName,
|
||||||
"url": "https://worldmonitor.app",
|
...(resolvedAuthorUrl ? { "url": resolvedAuthorUrl } : {})
|
||||||
"logo": {
|
|
||||||
"@type": "ImageObject",
|
|
||||||
"url": "https://www.worldmonitor.app/favico/apple-touch-icon.png"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"publisher": {
|
"publisher": {
|
||||||
"@type": "Organization",
|
"@type": "Organization",
|
||||||
@@ -72,6 +86,27 @@ const jsonLd = {
|
|||||||
"url": Astro.url.href,
|
"url": Astro.url.href,
|
||||||
...(keywords ? { "keywords": keywords } : {})
|
...(keywords ? { "keywords": keywords } : {})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function extractFaqLd(body: string | undefined): object | null {
|
||||||
|
if (!body) return null;
|
||||||
|
const faqIdx = body.indexOf('## Frequently Asked Questions');
|
||||||
|
if (faqIdx === -1) return null;
|
||||||
|
const afterFaq = body.slice(faqIdx + '## Frequently Asked Questions'.length);
|
||||||
|
const nextHeading = afterFaq.search(/\n##\s/);
|
||||||
|
const faqSection = nextHeading === -1 ? afterFaq : afterFaq.slice(0, nextHeading);
|
||||||
|
const qaRegex = /\*\*(.+?)\*\*\n([^\n*]+(?:\n[^\n*#]+)*)/g;
|
||||||
|
const items: { "@type": string; name: string; acceptedAnswer: { "@type": string; text: string } }[] = [];
|
||||||
|
let match: RegExpExecArray | null;
|
||||||
|
while ((match = qaRegex.exec(faqSection)) !== null) {
|
||||||
|
const q = match[1].trim();
|
||||||
|
const a = match[2].replace(/\[([^\]]+)\]\([^)]+\)/g, '$1').trim();
|
||||||
|
if (q && a) items.push({ "@type": "Question", name: q, acceptedAnswer: { "@type": "Answer", text: a } });
|
||||||
|
}
|
||||||
|
if (items.length === 0) return null;
|
||||||
|
return { "@context": "https://schema.org", "@type": "FAQPage", "mainEntity": items };
|
||||||
|
}
|
||||||
|
|
||||||
|
const faqLd = extractFaqLd(rawBody);
|
||||||
---
|
---
|
||||||
|
|
||||||
<Base
|
<Base
|
||||||
@@ -82,16 +117,19 @@ const jsonLd = {
|
|||||||
ogType="article"
|
ogType="article"
|
||||||
ogImage={ogImage}
|
ogImage={ogImage}
|
||||||
publishedTime={isoDate}
|
publishedTime={isoDate}
|
||||||
modifiedTime={isoDate}
|
modifiedTime={isoModifiedDate}
|
||||||
|
author={authorName}
|
||||||
section={audience}
|
section={audience}
|
||||||
jsonLd={jsonLd}
|
jsonLd={jsonLd}
|
||||||
breadcrumbLd={breadcrumbLd}
|
breadcrumbLd={breadcrumbLd}
|
||||||
|
faqLd={faqLd ?? undefined}
|
||||||
>
|
>
|
||||||
<article>
|
<article>
|
||||||
<div class="article-header">
|
<div class="article-header">
|
||||||
<a href="/blog/" class="back">← All articles</a>
|
<a href="/blog/" class="back">← All articles</a>
|
||||||
<div class="meta">
|
<div class="meta">
|
||||||
<time datetime={isoDate}>{formattedDate}</time>
|
<time datetime={isoDate}>{formattedDate}</time>
|
||||||
|
{showUpdated && <span> · Updated <time datetime={isoModifiedDate}>{formattedModifiedDate}</time></span>}
|
||||||
{audience && <span> · {audience}</span>}
|
{audience && <span> · {audience}</span>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -107,5 +145,17 @@ const jsonLd = {
|
|||||||
<p>Markets, geopolitics, conflicts, infrastructure. One dashboard. No login required.</p>
|
<p>Markets, geopolitics, conflicts, infrastructure. One dashboard. No login required.</p>
|
||||||
<a href="https://worldmonitor.app" class="btn" target="_blank" rel="noopener noreferrer">Open Dashboard</a>
|
<a href="https://worldmonitor.app" class="btn" target="_blank" rel="noopener noreferrer">Open Dashboard</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="author-bio">
|
||||||
|
<img src={avatarSrc} alt={authorName} width="48" height="48" class="author-avatar" loading="lazy" onerror="this.src='/favico/apple-touch-icon.png'" />
|
||||||
|
<div class="author-info">
|
||||||
|
<div class="author-name">
|
||||||
|
{resolvedAuthorUrl
|
||||||
|
? <a href={resolvedAuthorUrl} target="_blank" rel="noopener noreferrer">{authorName}</a>
|
||||||
|
: <span>{authorName}</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
{resolvedAuthorBio && <div class="author-desc" set:html={resolvedAuthorBio} />}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</article>
|
</article>
|
||||||
</Base>
|
</Base>
|
||||||
|
|||||||
@@ -20,9 +20,14 @@ const { Content } = await render(post);
|
|||||||
metaTitle={post.data.metaTitle}
|
metaTitle={post.data.metaTitle}
|
||||||
keywords={post.data.keywords}
|
keywords={post.data.keywords}
|
||||||
pubDate={post.data.pubDate}
|
pubDate={post.data.pubDate}
|
||||||
|
modifiedDate={post.data.modifiedDate}
|
||||||
|
author={post.data.author}
|
||||||
|
authorUrl={post.data.authorUrl}
|
||||||
|
authorBio={post.data.authorBio}
|
||||||
audience={post.data.audience}
|
audience={post.data.audience}
|
||||||
heroImage={post.data.heroImage}
|
heroImage={post.data.heroImage}
|
||||||
slug={post.id}
|
slug={post.id}
|
||||||
|
rawBody={post.body}
|
||||||
>
|
>
|
||||||
<Content />
|
<Content />
|
||||||
</BlogPost>
|
</BlogPost>
|
||||||
|
|||||||
@@ -573,6 +573,49 @@ img { max-width: 100%; height: auto; border-radius: var(--radius); }
|
|||||||
color: var(--wm-bg);
|
color: var(--wm-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ─── Author Bio ─── */
|
||||||
|
.author-bio {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 1rem;
|
||||||
|
margin: 2.5rem auto 0;
|
||||||
|
max-width: 720px;
|
||||||
|
padding: 1.25rem 1.5rem;
|
||||||
|
background: rgba(255,255,255,0.04);
|
||||||
|
border: 1px solid rgba(255,255,255,0.08);
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.author-avatar {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 50%;
|
||||||
|
flex-shrink: 0;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.author-info { flex: 1; }
|
||||||
|
|
||||||
|
.author-name {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text);
|
||||||
|
margin-bottom: 0.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.author-name a {
|
||||||
|
color: var(--wm-green);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.author-name a:hover { text-decoration: underline; }
|
||||||
|
|
||||||
|
.author-desc {
|
||||||
|
font-size: 0.82rem;
|
||||||
|
color: var(--text-dim);
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
/* ─── Responsive ─── */
|
/* ─── Responsive ─── */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.blog-hero h1 { font-size: 2rem; }
|
.blog-hero h1 { font-size: 2rem; }
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<!-- Primary Meta Tags -->
|
<!-- Primary Meta Tags -->
|
||||||
<title>World Monitor - Real-Time Global Intelligence Dashboard</title>
|
<title>World Monitor - Real-Time Global Intelligence Dashboard</title>
|
||||||
<meta name="title" content="World Monitor - Real-Time Global Intelligence Dashboard" />
|
<meta name="title" content="World Monitor - Real-Time Global Intelligence Dashboard" />
|
||||||
<meta name="description" content="AI-powered real-time global intelligence dashboard with live news, markets, military tracking, infrastructure monitoring, and geopolitical data. OSINT in one view." />
|
<meta name="description" content="AI-powered real-time global intelligence dashboard with live news, markets, military tracking, and geopolitical data. OSINT in one view." />
|
||||||
<meta name="keywords" content="AI intelligence, AI-powered dashboard, global intelligence, geopolitical dashboard, world news, market data, military bases, nuclear facilities, undersea cables, conflict zones, real-time monitoring, situation awareness, OSINT, flight tracking, AIS ships, earthquake monitor, protest tracker, power outages, oil prices, government spending, polymarket predictions" />
|
<meta name="keywords" content="AI intelligence, AI-powered dashboard, global intelligence, geopolitical dashboard, world news, market data, military bases, nuclear facilities, undersea cables, conflict zones, real-time monitoring, situation awareness, OSINT, flight tracking, AIS ships, earthquake monitor, protest tracker, power outages, oil prices, government spending, polymarket predictions" />
|
||||||
<meta name="author" content="Elie Habib" />
|
<meta name="author" content="Elie Habib" />
|
||||||
<meta name="theme-color" content="#0a0f0a" />
|
<meta name="theme-color" content="#0a0f0a" />
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
"name": "World Monitor",
|
"name": "World Monitor",
|
||||||
"alternateName": "World Monitor",
|
"alternateName": "World Monitor",
|
||||||
"url": "https://www.worldmonitor.app/",
|
"url": "https://www.worldmonitor.app/",
|
||||||
"description": "Open-source real-time OSINT dashboard for geopolitical monitoring, conflict tracking, military flight tracking, maritime AIS, and global threat intelligence. Used by 2M+ people across 190+ countries.",
|
"description": "Open-source real-time global intelligence dashboard aggregating conflicts, military movements, markets, infrastructure, and geopolitical data. Used by 2M+ people across 190+ countries. Featured in WIRED.",
|
||||||
"applicationCategory": "SecurityApplication",
|
"applicationCategory": "SecurityApplication",
|
||||||
"operatingSystem": "Web, Windows, macOS, Linux",
|
"operatingSystem": "Web, Windows, macOS, Linux",
|
||||||
"offers": [
|
"offers": [
|
||||||
@@ -87,7 +87,6 @@
|
|||||||
"name": "Elie Habib",
|
"name": "Elie Habib",
|
||||||
"url": "https://x.com/eliehabib",
|
"url": "https://x.com/eliehabib",
|
||||||
"jobTitle": "CEO",
|
"jobTitle": "CEO",
|
||||||
"worksFor": { "@type": "Organization", "name": "Anghami", "url": "https://anghami.com" },
|
|
||||||
"sameAs": ["https://x.com/eliehabib", "https://github.com/koala73"]
|
"sameAs": ["https://x.com/eliehabib", "https://github.com/koala73"]
|
||||||
},
|
},
|
||||||
"featureList": [
|
"featureList": [
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ const SOCIAL_IMAGE_UA =
|
|||||||
const VARIANT_HOST_MAP: Record<string, string> = {
|
const VARIANT_HOST_MAP: Record<string, string> = {
|
||||||
'tech.worldmonitor.app': 'tech',
|
'tech.worldmonitor.app': 'tech',
|
||||||
'finance.worldmonitor.app': 'finance',
|
'finance.worldmonitor.app': 'finance',
|
||||||
|
'commodity.worldmonitor.app': 'commodity',
|
||||||
'happy.worldmonitor.app': 'happy',
|
'happy.worldmonitor.app': 'happy',
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -31,6 +32,12 @@ const VARIANT_OG: Record<string, { title: string; description: string; image: st
|
|||||||
image: 'https://finance.worldmonitor.app/favico/finance/og-image.png',
|
image: 'https://finance.worldmonitor.app/favico/finance/og-image.png',
|
||||||
url: 'https://finance.worldmonitor.app/',
|
url: 'https://finance.worldmonitor.app/',
|
||||||
},
|
},
|
||||||
|
commodity: {
|
||||||
|
title: 'Commodity Monitor - Real-Time Commodity Markets & Supply Chain Dashboard',
|
||||||
|
description: 'Real-time commodity markets dashboard tracking mining sites, processing plants, commodity ports, supply chains, and global commodity trade flows.',
|
||||||
|
image: 'https://commodity.worldmonitor.app/favico/commodity/og-image.png',
|
||||||
|
url: 'https://commodity.worldmonitor.app/',
|
||||||
|
},
|
||||||
happy: {
|
happy: {
|
||||||
title: 'Happy Monitor - Good News & Global Progress',
|
title: 'Happy Monitor - Good News & Global Progress',
|
||||||
description: 'Curated positive news, progress data, and uplifting stories from around the world.',
|
description: 'Curated positive news, progress data, and uplifting stories from around the world.',
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
World Monitor is an open-source (AGPL-3.0) intelligence platform that aggregates 435+ news feeds, 45+ interactive map layers, and multiple AI models into a single dashboard. Used by 2M+ people across 190+ countries, as featured in WIRED. It runs as a web app, installable PWA, and native desktop application (Tauri) for macOS, Windows, and Linux.
|
World Monitor is an open-source (AGPL-3.0) intelligence platform that aggregates 435+ news feeds, 45+ interactive map layers, and multiple AI models into a single dashboard. Used by 2M+ people across 190+ countries, as featured in WIRED. It runs as a web app, installable PWA, and native desktop application (Tauri) for macOS, Windows, and Linux.
|
||||||
|
|
||||||
A single codebase produces three specialized variants — geopolitical, technology, and finance — each with distinct feeds, panels, map layers, and branding. The tri-variant architecture uses build-time selection via the VITE_VARIANT environment variable, with runtime switching available via the header bar.
|
A single codebase produces five specialized variants — geopolitical (World Monitor), technology (Tech Monitor), finance (Finance Monitor), commodities (Commodity Monitor), and positive news (Happy Monitor) — each with distinct feeds, panels, map layers, and branding. The multi-variant architecture uses build-time selection via the VITE_VARIANT environment variable, with runtime switching available via the header bar.
|
||||||
|
|
||||||
The project is built with TypeScript, Vite, MapLibre GL JS, deck.gl, D3.js, and Tauri. All intelligence analysis (clustering, instability scoring, surge detection) runs client-side in the browser — no backend compute dependency for core intelligence. A browser-side ML pipeline (Transformers.js) provides NER and sentiment analysis without server dependency.
|
The project is built with TypeScript, Vite, MapLibre GL JS, deck.gl, D3.js, and Tauri. All intelligence analysis (clustering, instability scoring, surge detection) runs client-side in the browser — no backend compute dependency for core intelligence. A browser-side ML pipeline (Transformers.js) provides NER and sentiment analysis without server dependency.
|
||||||
|
|
||||||
@@ -13,6 +13,8 @@ The project is built with TypeScript, Vite, MapLibre GL JS, deck.gl, D3.js, and
|
|||||||
- [World Monitor](https://worldmonitor.app): Geopolitics, military, conflicts, infrastructure
|
- [World Monitor](https://worldmonitor.app): Geopolitics, military, conflicts, infrastructure
|
||||||
- [Tech Monitor](https://tech.worldmonitor.app): Startups, AI/ML, cloud, cybersecurity
|
- [Tech Monitor](https://tech.worldmonitor.app): Startups, AI/ML, cloud, cybersecurity
|
||||||
- [Finance Monitor](https://finance.worldmonitor.app): Global markets, trading, central banks, Gulf FDI
|
- [Finance Monitor](https://finance.worldmonitor.app): Global markets, trading, central banks, Gulf FDI
|
||||||
|
- [Commodity Monitor](https://commodity.worldmonitor.app): Mining, metals, energy, supply chains, commodity markets
|
||||||
|
- [Happy Monitor](https://happy.worldmonitor.app): Positive news, breakthroughs, conservation, renewable energy
|
||||||
- [World Monitor Pro](https://worldmonitor.app/pro): AI-powered equity research, geopolitical analysis, macro intelligence
|
- [World Monitor Pro](https://worldmonitor.app/pro): AI-powered equity research, geopolitical analysis, macro intelligence
|
||||||
- [Blog](https://www.worldmonitor.app/blog/): Analysis, OSINT guides, geopolitics, and market intelligence articles
|
- [Blog](https://www.worldmonitor.app/blog/): Analysis, OSINT guides, geopolitics, and market intelligence articles
|
||||||
|
|
||||||
@@ -57,6 +59,26 @@ The project is built with TypeScript, Vite, MapLibre GL JS, deck.gl, D3.js, and
|
|||||||
- **AI**: Groq (Llama 3.1), OpenRouter, browser-side T5 fallback
|
- **AI**: Groq (Llama 3.1), OpenRouter, browser-side T5 fallback
|
||||||
- **Monitoring**: Sentry error tracking, data freshness tracker across 22 sources
|
- **Monitoring**: Sentry error tracking, data freshness tracker across 22 sources
|
||||||
|
|
||||||
|
## Blog Posts
|
||||||
|
|
||||||
|
- [What Is World Monitor?](https://www.worldmonitor.app/blog/posts/what-is-worldmonitor-real-time-global-intelligence/): Overview of the platform, features, and use cases
|
||||||
|
- [Five Dashboards, One Platform](https://www.worldmonitor.app/blog/posts/five-dashboards-one-platform-worldmonitor-variants/): Guide to all five dashboard variants
|
||||||
|
- [Track Global Conflicts in Real Time](https://www.worldmonitor.app/blog/posts/track-global-conflicts-in-real-time/): Conflict monitoring using ACLED, UCDP, and Telegram OSINT
|
||||||
|
- [OSINT for Everyone](https://www.worldmonitor.app/blog/posts/osint-for-everyone-open-source-intelligence-democratized/): How open-source intelligence is democratized
|
||||||
|
- [Natural Disaster Monitoring](https://www.worldmonitor.app/blog/posts/natural-disaster-monitoring-earthquakes-fires-volcanoes/): USGS earthquakes, NASA FIRMS fires, volcanic activity
|
||||||
|
- [Real-Time Market Intelligence](https://www.worldmonitor.app/blog/posts/real-time-market-intelligence-for-traders-and-analysts/): Financial markets, Fear & Greed, ETF flows
|
||||||
|
- [Cyber Threat Intelligence](https://www.worldmonitor.app/blog/posts/cyber-threat-intelligence-for-security-teams/): Feodo Tracker, URLhaus, botnet C2 monitoring
|
||||||
|
- [Global Supply Chain Monitoring](https://www.worldmonitor.app/blog/posts/monitor-global-supply-chains-and-commodity-disruptions/): Ports, chokepoints, commodity disruptions
|
||||||
|
- [Satellite Imagery and Orbital Surveillance](https://www.worldmonitor.app/blog/posts/satellite-imagery-orbital-surveillance/): SAR, EO, and OSINT satellite data
|
||||||
|
- [Live Webcams from Geopolitical Hotspots](https://www.worldmonitor.app/blog/posts/live-webcams-from-geopolitical-hotspots/): Real-time visual feeds from conflict zones
|
||||||
|
- [Prediction Markets and AI Forecasting](https://www.worldmonitor.app/blog/posts/prediction-markets-ai-forecasting-geopolitics/): Polymarket integration and geopolitical forecasting
|
||||||
|
- [World Monitor in 21 Languages](https://www.worldmonitor.app/blog/posts/worldmonitor-in-21-languages-global-intelligence-for-everyone/): Multilingual global intelligence platform
|
||||||
|
- [Command Palette Search](https://www.worldmonitor.app/blog/posts/command-palette-search-everything-instantly/): Cmd+K fuzzy search across all data layers
|
||||||
|
- [AI-Powered Intelligence Without the Cloud](https://www.worldmonitor.app/blog/posts/ai-powered-intelligence-without-the-cloud/): Local LLMs, Ollama, offline-first AI analysis
|
||||||
|
- [Build on World Monitor](https://www.worldmonitor.app/blog/posts/build-on-worldmonitor-developer-api-open-source/): Developer API, proto definitions, open-source contribution
|
||||||
|
- [World Monitor vs Traditional Intelligence Tools](https://www.worldmonitor.app/blog/posts/worldmonitor-vs-traditional-intelligence-tools/): Comparison with Bloomberg, Palantir, Dataminr, Recorded Future
|
||||||
|
- [Tracking Global Trade Routes](https://www.worldmonitor.app/blog/posts/tracking-global-trade-routes-chokepoints-freight-costs/): Maritime chokepoints, freight costs, trade flow analysis
|
||||||
|
|
||||||
## Optional
|
## Optional
|
||||||
|
|
||||||
- [Source Code](https://github.com/koala73/worldmonitor): GitHub repository (AGPL-3.0)
|
- [Source Code](https://github.com/koala73/worldmonitor): GitHub repository (AGPL-3.0)
|
||||||
|
|||||||
@@ -1,29 +1,10 @@
|
|||||||
# World Monitor - protect API routes from crawlers
|
# World Monitor - protect API routes from crawlers
|
||||||
User-agent: *
|
User-agent: *
|
||||||
Allow: /
|
Allow: /
|
||||||
|
Allow: /api/story
|
||||||
|
Allow: /api/og-story
|
||||||
Disallow: /api/
|
Disallow: /api/
|
||||||
Disallow: /tests/
|
Disallow: /tests/
|
||||||
|
|
||||||
Sitemap: https://www.worldmonitor.app/sitemap.xml
|
Sitemap: https://www.worldmonitor.app/sitemap.xml
|
||||||
Sitemap: https://www.worldmonitor.app/blog/sitemap-index.xml
|
Sitemap: https://www.worldmonitor.app/blog/sitemap-index.xml
|
||||||
|
|
||||||
# Allow social media bots for OG previews
|
|
||||||
User-agent: Twitterbot
|
|
||||||
Allow: /api/story
|
|
||||||
Allow: /api/og-story
|
|
||||||
|
|
||||||
User-agent: facebookexternalhit
|
|
||||||
Allow: /api/story
|
|
||||||
Allow: /api/og-story
|
|
||||||
|
|
||||||
User-agent: LinkedInBot
|
|
||||||
Allow: /api/story
|
|
||||||
Allow: /api/og-story
|
|
||||||
|
|
||||||
User-agent: Slackbot
|
|
||||||
Allow: /api/story
|
|
||||||
Allow: /api/og-story
|
|
||||||
|
|
||||||
User-agent: Discordbot
|
|
||||||
Allow: /api/story
|
|
||||||
Allow: /api/og-story
|
|
||||||
|
|||||||
@@ -24,6 +24,12 @@
|
|||||||
<changefreq>daily</changefreq>
|
<changefreq>daily</changefreq>
|
||||||
<priority>0.8</priority>
|
<priority>0.8</priority>
|
||||||
</url>
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://commodity.worldmonitor.app/</loc>
|
||||||
|
<lastmod>2026-03-26</lastmod>
|
||||||
|
<changefreq>daily</changefreq>
|
||||||
|
<priority>0.8</priority>
|
||||||
|
</url>
|
||||||
<url>
|
<url>
|
||||||
<loc>https://happy.worldmonitor.app/</loc>
|
<loc>https://happy.worldmonitor.app/</loc>
|
||||||
<lastmod>2026-03-19</lastmod>
|
<lastmod>2026-03-19</lastmod>
|
||||||
|
|||||||
Reference in New Issue
Block a user