Features
Other Frameworks
AltiusSEO.Core is frontend-agnostic. The .NET backend works with any frontend stack. Only the admin dashboard component requires Next.js.
How it works: Your frontend talks to the /api/seo/* endpoints exposed by your .NET backend. Any HTTP-capable frontend can consume them.
Angular
TypeScript + RxJSUse the raw HTTP API from Angular services. No npm package needed — call the endpoints directly.
1. Create an SEO service
// seo.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({ providedIn: 'root' })
export class SeoService {
private readonly api = '/api/seo';
private readonly siteId = 'my-site';
constructor(private http: HttpClient) {}
trackPageView(url: string, title: string) {
return this.http.post(`${this.api}/track`, {
siteId: this.siteId,
pageUrl: url,
pageTitle: title,
referrer: document.referrer,
userAgent: navigator.userAgent,
}).subscribe();
}
checkRedirect(path: string) {
return this.http.get<{ redirectUrl: string; statusCode: number }>(
`${this.api}/redirect/match?siteId=${this.siteId}&path=${encodeURIComponent(path)}`
);
}
}2. Track page views in the router
// app.component.ts
import { Component, OnInit } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import { SeoService } from './seo.service';
import { filter } from 'rxjs/operators';
@Component({ selector: 'app-root', template: '<router-outlet />' })
export class AppComponent implements OnInit {
constructor(private router: Router, private seo: SeoService) {}
ngOnInit() {
this.router.events
.pipe(filter(e => e instanceof NavigationEnd))
.subscribe((e: NavigationEnd) => {
this.seo.trackPageView(e.urlAfterRedirects, document.title);
});
}
}3. Handle redirects in a route guard
// redirect.guard.ts
import { inject } from '@angular/core';
import { Router, CanActivateFn } from '@angular/router';
import { SeoService } from './seo.service';
import { map, catchError, of } from 'rxjs';
export const redirectGuard: CanActivateFn = (route, state) => {
const seo = inject(SeoService);
const router = inject(Router);
return seo.checkRedirect(state.url).pipe(
map(result => {
if (result?.redirectUrl) {
window.location.href = result.redirectUrl;
return false;
}
return true;
}),
catchError(() => of(true))
);
};Admin dashboard for Angular apps
Embed the Next.js dashboard as a separate admin app, or use the raw admin API endpoints to build your own Angular admin UI.
React (SPA / Vite)
No Next.js requiredFor React apps not using Next.js (Vite, Create React App, etc.), install the npm package and use the lower-level hooks directly.
npm install @altiusseo/next
Setup
// main.tsx
import { SEOProvider, SEOTracker } from '@altiusseo/next';
function App() {
return (
<SEOProvider apiUrl="https://your-api.com/api/seo" siteId="my-site">
<Router>
<Routes />
</Router>
<SEOTracker /> {/* auto-tracks route changes */}
</SEOProvider>
);
}Per-page SEO
// pages/BlogPost.tsx
import { SEOHead } from '@altiusseo/next';
export function BlogPost({ post }) {
return (
<>
<SEOHead
title={post.title}
description={post.excerpt}
canonical={`https://mysite.com/blog/${post.slug}`}
/>
<article>{post.content}</article>
</>
);
}Note: SEOHead uses document.title and meta tags directly in SPA mode. For SSR/SSG (better for SEO), use Next.js with the full setup.
Blazor
WebAssembly + ServerBlazor apps share the same .NET backend — add AltiusSEO.Core once and consume it from both Blazor and any other frontend.
Backend setup (same as Next.js)
// Program.cs
builder.Services.AddAltiusSEO(options => {
options.ConnectionString = builder.Configuration.GetConnectionString("Default");
options.SiteId = "my-site";
});
app.UseAltiusSEODatabase();
app.MapAltiusSEO();
app.MapAltiusSEOAdmin();Track page views from Blazor
// SeoTracker.razor
@inject HttpClient Http
@inject NavigationManager Nav
@implements IDisposable
@code {
protected override void OnInitialized() {
Nav.LocationChanged += OnNavigated;
_ = TrackAsync(Nav.Uri);
}
private void OnNavigated(object? _, LocationChangedEventArgs e) => _ = TrackAsync(e.Location);
private async Task TrackAsync(string url) {
await Http.PostAsJsonAsync("/api/seo/track", new {
siteId = "my-site",
pageUrl = url,
pageTitle = ""
});
}
public void Dispose() => Nav.LocationChanged -= OnNavigated;
}Add <SeoTracker /> to your MainLayout.razor.
ASP.NET MVC / Razor Pages
Server-renderedFor traditional server-rendered .NET apps, inject the SEO service directly and render meta tags in your Razor views.
Inject the SEO service in a controller
// Controllers/BlogController.cs
using AltiusSEO.Core.Services;
public class BlogController : Controller {
private readonly ISeoMetaService _seo;
public BlogController(ISeoMetaService seo) {
_seo = seo;
}
public async Task<IActionResult> Post(string slug) {
var post = await GetPostAsync(slug);
var meta = await _seo.GetPageMetaAsync("my-site", Request.Path);
ViewBag.Title = meta?.Title ?? post.Title;
ViewBag.Description = meta?.Description ?? post.Excerpt;
ViewBag.OgImage = meta?.OgImage ?? post.CoverImage;
return View(post);
}
}Render in your Razor layout
@* Views/Shared/_Layout.cshtml *@
<head>
<title>@ViewBag.Title</title>
<meta name="description" content="@ViewBag.Description" />
<meta property="og:title" content="@ViewBag.Title" />
<meta property="og:description" content="@ViewBag.Description" />
@if (ViewBag.OgImage != null) {
<meta property="og:image" content="@ViewBag.OgImage" />
}
</head>The admin dashboard is still available by embedding the SEODashboard component in a Next.js app pointed at the same backend, or by building your own Razor admin views using the admin API endpoints.
Vanilla JS / Any Frontend
HTTP API onlyAny frontend can consume the SEO tracking API with a simple fetch call.
// Minimal tracker — paste into any site
const SEO_API = 'https://your-api.com/api/seo';
const SITE_ID = 'my-site';
async function trackPageView() {
await fetch(`${SEO_API}/track`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
siteId: SITE_ID,
pageUrl: window.location.pathname,
pageTitle: document.title,
referrer: document.referrer,
userAgent: navigator.userAgent,
}),
});
}
// Track on load and on SPA navigation
trackPageView();
window.addEventListener('popstate', trackPageView);Compatibility Summary
| Frontend | Tracking | Redirects | Admin Dashboard |
|---|---|---|---|
| Next.js 14+ | ✓ Native | ✓ Middleware | ✓ Full SEODashboard component |
| React (SPA) | ✓ SEOTracker | ⚡ Client-side | ✓ SEODashboard component |
| Angular | ✓ HTTP service | ✓ Route guard | ⚡ Build own or use Next.js admin |
| Blazor | ✓ HttpClient | ✓ NavManager | ⚡ Build own or use Next.js admin |
| ASP.NET MVC | ✓ JS snippet | ✓ Middleware | ⚡ Build own or use Next.js admin |
| Vanilla JS | ✓ fetch() | ⚡ Manual | ⚡ Build own or use Next.js admin |