Admin Guide
Everything you need to know about managing your Contento site from the admin panel.
Dashboard
The dashboard is your starting point after logging in. It provides an at-a-glance overview of your site, including:
- Total Posts — Count of all posts across all statuses (draft, published, scheduled)
- Published Posts — Number of currently live posts
- Comments — Total comments and pending moderation queue count
- Media Files — Number of files in the media library
- Recent Activity — Latest posts, comments, and changes
Managing Posts
Creating a post
- Navigate to Posts in the sidebar.
- Click New Post.
- Enter a title. The slug is auto-generated but can be customized.
- Write content in the Markdown editor. The live preview updates in real-time.
- Optionally add: subtitle, excerpt, cover image, tags, category, and SEO metadata.
- Click Save Draft to save without publishing, or Publish to make it live.
Editing posts
Click any post title in the posts list to open the editor. Changes are autosaved as you type. The version counter increments on each save, and previous versions are tracked for recovery.
Publishing and scheduling
- Publish — Immediately makes the post visible on the public site
- Schedule — Set a future date/time. The post goes live automatically when the scheduled time arrives.
- Unpublish — Reverts a published post back to draft status, removing it from the public site
Post statuses
| Status | Description |
|---|---|
draft | Work in progress. Only visible to admins. |
published | Live on the public site. |
scheduled | Will be auto-published at the set date/time. |
Visibility options
| Visibility | Description |
|---|---|
public | Visible to everyone. |
private | Only visible to logged-in users. |
password | Requires a password to view. |
Bulk actions
In the posts list, select multiple posts using the checkboxes and use the bulk action menu to:
- Publish selected posts
- Unpublish selected posts
- Delete selected posts
- Assign a category to selected posts
Media Library
Uploading files
Navigate to Media in the sidebar. Drag and drop files onto the upload area, or click to browse. You can upload multiple files at once.
Supported formats
| Type | Formats | MIME Types |
|---|---|---|
| Images | JPEG, PNG, GIF, WebP, SVG | image/jpeg, image/png, image/gif, image/webp, image/svg+xml |
| Documents | application/pdf | |
| Video | MP4 | video/mp4 |
FILE_TOO_LARGE error.
Organizing media
The media library provides a rich set of tools for organizing your files:
- Folders — Organize files into folders. Create folders and move files between them.
- Grid/List view — Toggle between grid thumbnails and detailed list view (persisted via localStorage).
- Bulk selection — Select multiple files with checkboxes for bulk delete or move operations.
- Search & filters — Search by filename and filter by file type (images, documents, video) or folder.
- Detail panel — Click any file to open a slide-out panel with metadata, alt text, caption, and a copy-URL button.
- Focal point picker — For images, click to set a focal point. This ensures cropped thumbnails focus on the right area.
- Infinite scroll — Media loads progressively as you scroll, powered by IntersectionObserver.
Responsive image variants
When you upload an image, Contento automatically generates optimized responsive variants using ImageSharp:
| Variant | Width | Format | Purpose |
|---|---|---|---|
| Thumbnail | 400px | WebP | Grid previews and cards |
| Small | 640px | WebP | Mobile devices |
| Medium | 1024px | WebP | Tablets and small screens |
| Large | 1536px | WebP | Desktop and retina displays |
EXIF metadata is automatically stripped from all variants for privacy and reduced file size. The original file is preserved at full resolution.
Using media in posts
In the post editor, click the image button or use the Markdown image syntax. The media picker shows all uploaded files with search and filtering.
# Markdown image syntax

Categories
Creating categories
Navigate to Categories in the sidebar. Click New Category and provide a name (the slug is auto-generated). Optionally set a description and a parent category.
Hierarchical structure
Categories support unlimited nesting. Each category has:
- Name — Display name
- Slug — URL-safe identifier (auto-generated from name)
- Description — Optional description
- Parent — Optional parent category for hierarchy
- Sort order — Controls display order within the same level
Assigning to posts
Each post can belong to one category. Set the category in the post editor's sidebar panel.
Comments
Moderation queue
New comments arrive with pending status and appear in the moderation queue.
From the Comments page you can:
- Approve — Makes the comment visible on the public post
- Mark as Spam — Moves the comment to the spam bin
- Delete — Permanently removes the comment
Comment statuses
| Status | Description |
|---|---|
pending | Awaiting moderation. Not visible publicly. |
approved | Visible on the post page. |
spam | Flagged as spam. Hidden from public. |
Batch actions
Select multiple comments and approve, spam, or delete them in bulk.
Honeypot protection
Contento uses a honeypot field (website) in the comment form. If a bot fills in this hidden field,
the comment is silently discarded without any error message. This reduces spam without CAPTCHAs.
AI spam scoring
In addition to the honeypot, Contento uses an AI-powered spam scoring system that analyzes comment content for spam patterns. Each comment receives a score from 0 to 1, where higher scores indicate more likely spam.
- Auto-approve threshold — Configure in Settings. Comments scoring below this threshold are auto-approved.
- Spam stats — View total approved, blocked, and checked counts in the Settings page.
- Pattern detection — Regex-based keyword detection for common spam patterns.
Threaded replies
Comments support nested threading via the parentId field. Replies are displayed
indented under their parent comment, with a depth value tracking nesting level.
Users
User roles
| Role | Permissions |
|---|---|
| owner | Full access to everything, including site deletion and user management |
| admin | Full access to content, themes, plugins, and settings. Cannot delete site. |
| editor | Can create, edit, and publish any post. Can moderate comments. Cannot manage users or settings. |
| author | Can create and edit own posts. Can submit for review. Cannot publish. |
| viewer | Read-only access to the admin dashboard. Cannot create or edit content. |
Managing accounts
Navigate to Users in the sidebar. You can:
- Invite new users by email
- Change a user's role
- Deactivate accounts (sets
isActiveto false) - Reset passwords
Themes
Activating a theme
Go to Themes in the sidebar. Each theme card shows a preview and description. Click Activate to apply the theme to your public site. Only one theme can be active at a time.
CSS variable system
Themes work by injecting CSS variables into the page. These variables control fonts, colors, spacing, and other visual properties. See the Theme Development guide for the full variable reference.
Built-in themes
| Theme | Description |
|---|---|
| Shizen | Nature-inspired minimalism. Warm paper tones with organic typography. |
| Koyo | Autumn leaves palette. Rich reds and warm browns evoking Japanese fall foliage. |
| Yuki | Winter snow theme. Clean whites with cool blue accents and crisp typography. |
| Ink | Dark mode calligraphy theme. Deep blacks with high-contrast text. |
| Grove | Forest green palette. Earthy tones with serif typography for long-form reading. |
| Neon | Vibrant modern design. Bold colors with sans-serif type for tech and creative blogs. |
| Folio | Portfolio-style layout. Minimal chrome that puts content and imagery front and center. |
| Dusk | Twilight color scheme. Muted purples and blues for a sophisticated evening mood. |
Layouts
What are layouts?
Layouts define the structural arrangement of content regions on a page. Each layout has a JSON structure
that describes which regions appear, their grid arrangement, and responsive behavior.
Built-in layouts
| Layout | Description |
|---|---|
| Standard Blog | Classic blog layout with main content area, sidebar, header, and footer. |
| Full Width | Single column layout that spans the full width. Ideal for landing pages and long-form articles. |
| Magazine | Multi-column grid layout with featured post hero section. Great for content-heavy sites. |
| Minimal | Stripped-down layout with just header, content, and footer. Maximum reading focus. |
Setting a default layout
One layout is marked as the default and is used for all posts that do not have a specific layout assigned. To change the default, click Set as Default on any layout.
Layout structure JSON
The structure field is a JSON object describing the page grid. See the
Theme Development guide for the full JSON specification and examples.
Navigation Menus
Overview
Contento includes a full menu management system, similar to WordPress menus. You can create named menus, assign them to display locations (header, footer, or custom), and add items that link to custom URLs, posts, categories, or tags. Items can be nested one level deep for dropdown support.
Creating a menu
Navigate to Menus in the admin sidebar. Use the “Add Menu” form to create a new menu with a name and location:
- Header — Renders in the public site header navigation
- Footer — Renders in the public site footer
- Custom — Available via the API for headless consumers
Adding menu items
Click Edit on a menu to manage its items. Each item has:
- Type — Custom Link, Post, Category, or Tag
- Label — The display text shown in the navigation
- URL — For custom links; post/category/tag URLs are resolved automatically
- Target — Open in same tab (_self) or new tab (_blank)
- Parent — Nest under an existing top-level item for dropdown menus
Reordering
Use the Up and Down arrows next to each item to reorder. Changes take effect immediately on the public site.
Default menus
Contento seeds two menus on first run:
| Menu | Location | Default Items |
|---|---|---|
| Main Navigation | Header | Home, Search |
| Footer | Footer | Home, RSS Feed |
GET /api/v1/content/menu/{location}.
URL Redirects
Overview
Contento includes built-in redirect management for handling moved or renamed content. Navigate to Redirects in the admin sidebar. Redirects are processed by middleware on all public GET requests, ensuring search engines and visitors are seamlessly sent to the correct URL.
Creating a redirect
Click Add Redirect and provide:
- From Path — The old URL path (e.g.,
/old-post-slug) - To Path — The new destination (e.g.,
/new-post-slug) - Status Code —
301(permanent) or302(temporary) - Notes — Optional note explaining why the redirect exists
- Active — Toggle to enable or disable the redirect
Hit tracking
Each redirect tracks how many times it has been triggered and the timestamp of the last hit. This helps you identify which redirects are still in use and which can be safely removed.
Auto-redirects
When a post slug is changed, Contento can automatically create a 301 redirect from the old slug to the new one, preserving SEO value and preventing broken links.
/api/, /admin/,
and /health paths for performance. Only public GET requests are evaluated.
User Registration & Password Reset
Public registration
Contento supports public user registration. Visitors can create an account from the /Register page by providing an email, display name, and password (minimum 8 characters). New accounts are created with the viewer role by default.
Email verification
After registration, a verification email is sent with a unique token link. Users must verify their email before gaining full access. The email verification status is visible in the admin Users page.
Password reset
Users who forget their password can request a reset from the /ResetPassword page:
- Enter your email address and click Send Reset Link.
- A reset email is sent with a secure token (valid for 1 hour).
- Click the link and enter a new password.
Gravatar avatars
User avatars are automatically loaded from Gravatar using the user's email address. If no Gravatar is configured, a default mystery-person icon is shown.
oEmbed & Rich Media
Overview
Contento automatically converts supported URLs in your content into rich embedded media. Paste a YouTube, Vimeo, Twitter, Spotify, SoundCloud, or CodePen URL into your post content and it will be rendered as an interactive embed on the public site.
Supported providers
| Provider | URL Patterns |
|---|---|
| YouTube | youtube.com/watch?v=..., youtu.be/... |
| Vimeo | vimeo.com/... |
| Twitter / X | twitter.com/.../status/..., x.com/.../status/... |
| Spotify | open.spotify.com/track/..., open.spotify.com/album/... |
| SoundCloud | soundcloud.com/... |
| CodePen | codepen.io/.../pen/... |
Caching
Embed lookups are cached in memory for 5 minutes to minimize external API calls. Unknown URLs are passed through unchanged.
Shortcodes
Overview
Shortcodes let you embed dynamic content in your posts using simple bracket syntax.
Write [shortcode attr="value"] in your Markdown and Contento expands it to HTML at render time.
Built-in shortcodes
| Shortcode | Example | Description |
|---|---|---|
[youtube] | [youtube id="dQw4w9WgXcQ"] | Embeds a YouTube video player |
[vimeo] | [vimeo id="123456"] | Embeds a Vimeo video player |
[button] | [button url="/signup" text="Sign Up"] | Renders a styled call-to-action button |
[callout] | [callout type="info"]Note text[/callout] | Highlighted callout box (info, warning, tip) |
[gallery] | [gallery ids="id1,id2,id3"] | Image gallery grid from media IDs |
[code] | [code lang="js"]var x = 1;[/code] | Syntax-highlighted code block |
[toc] | [toc] | Auto-generated table of contents from headings |
Custom shortcodes
You can register custom shortcodes at runtime via the plugin system. Custom shortcodes receive the tag name, attributes, inner content, and a context object with the current PostId, SiteId, and BaseUrl.
Plugins
Plugin overview
Plugins extend Contento's functionality by running JavaScript code in a sandboxed environment (Jint). They can modify rendered post content by hooking into the rendering pipeline.
Enabling and disabling
Navigate to Plugins in the sidebar. Each installed plugin shows its name, version, author, and status. Toggle the switch to enable or disable a plugin.
Installing via the UI
- Click Install Plugin on the Plugins page.
- Provide the plugin name, slug, version, and JavaScript entry point code.
- Click Install. The plugin is enabled immediately.
Plugin settings
Each plugin has a JSON settings object. Click the gear icon on a plugin card to
open the settings editor. Settings are passed to the plugin as the global PLUGIN_SETTINGS object.
For more details on building plugins, see the Plugin Development guide.
Settings
Site configuration
Navigate to Settings in the sidebar to configure core site properties:
| Setting | Description | Example |
|---|---|---|
| Site Name | The name displayed in the header, feeds, and metadata | My Awesome Blog |
| Tagline | A short description or subtitle | Thoughts on software engineering |
| Locale | Language and region code | en-US, ja-JP |
| Timezone | Timezone for date display and scheduling | UTC, America/New_York |
| Custom Domain | Your own domain name for the site | blog.example.com |
Spam protection
The Settings page includes a spam protection section where you can:
- Auto-Approve Threshold — Slider from 0-100%. Comments scoring below this threshold are auto-approved. Higher = more lenient.
- Spam Statistics — View total approved, blocked, and checked comment counts.
- Moderation Queue — Quick link to the Comments moderation page.
Newsletter
Overview
The Newsletter section lets you manage email subscribers and campaigns. Navigate to Newsletter in the sidebar.
Subscribers
The Subscribers tab shows all newsletter subscribers with their status:
- Active — Currently subscribed and receiving emails
- Unsubscribed — Opted out of newsletters
Subscribers sign up via the public newsletter form in the site footer. You can also view subscriber email, signup date, and membership tier.
Campaigns
Create email campaigns from the Campaigns tab:
- Click New Campaign.
- Enter a subject line and compose the email body.
- Preview the campaign before sending.
- Click Send to deliver to all active subscribers, or save as draft.
Campaign statuses: draft, scheduled, sent.
Membership
Overview
The Membership section manages paid subscriptions powered by Stripe. Navigate to Membership in the sidebar.
The membership admin has four tabs:
Dashboard tab
Shows key metrics at a glance:
- Total Subscribers — All registered members (free + paid)
- Paid Members — Subscribers with an active paid plan
- Active Plans — Number of plans currently enabled
Plans tab
Create and manage membership plans:
- Plan Name — Display name (e.g., Premium, VIP)
- Slug — URL-safe identifier
- Price — Amount in dollars
- Billing Interval — Monthly, Yearly, or Lifetime
- Stripe Price ID — Link to your Stripe price object (e.g.,
price_...) - Trial Days — Number of free trial days before billing starts
- Access Level — Integer level for content gating (higher = more access)
- Features — Bullet-point list displayed on the public pricing page
Members tab
View all subscribers with their membership details: email, tier (free/premium/VIP), status (active/expired), Stripe customer ID, expiry date, and join date.
Settings tab
Configure membership behavior:
- Grace Period — Number of days to maintain access after expiration
- Dunning Email Template — Email sent when a payment fails. Use
{portal_url}placeholder. - Drip Content Delay — Default delay before new members access drip content
Multi-Site Management
Contento supports running multiple sites from a single installation. Navigate to Sites in the sidebar.
How it works
Each site has its own content, themes, settings, and domain. Sites are resolved by the Host header
using domain-based routing. If no domain matches, the primary site is used as fallback.
Managing sites
- Create Site — Provide a name, slug, and optional domain. A new site starts with default settings.
- Set Primary — Mark one site as the primary (default) site.
- Delete Site — Remove a site and all its content. Cannot delete the primary site.
Site switcher
The admin navigation includes a site switcher dropdown, allowing you to switch between sites without logging out.
Task Scheduler
The Task Scheduler automates recurring operations. Navigate to Scheduler in the sidebar.
Creating tasks
- Task Name — A descriptive name for the scheduled task
- Task Type — Choose from 6 built-in types (e.g., cache clearing, sitemap generation)
- Cron Expression — Standard cron syntax for scheduling, with quick presets (every hour, daily, weekly)
- Enabled — Toggle tasks on/off
Monitoring
Each task shows its last run time, next scheduled run, and current status. You can manually trigger any task from the admin UI.
Custom Post Types
Beyond standard blog posts, you can define custom content types. Navigate to Post Types in the sidebar.
Creating a post type
- Name — Display name (e.g., Recipe, Portfolio, Review)
- Slug — URL-safe identifier
- Icon — Emoji or icon identifier for the sidebar
- Field Schema — JSON schema defining custom fields for this content type
Posts can then be assigned to a post type, and the editor will show the appropriate custom fields.
Audit Log
The audit log records every significant action performed in the admin panel. Navigate to Audit Log in the sidebar to view a chronological list of changes.
Each audit log entry records:
- Timestamp — When the action occurred (UTC)
- User — Who performed the action
- Action — What was done (create, update, delete, publish, etc.)
- Entity type — What type of object was affected (post, comment, user, theme, etc.)
- Entity ID — The ID of the affected object
- Details — Additional context about the change