Skip to content

Quick Start Guide

Get your Astro site connected to Aether CMS and start editing content visually in under 5 minutes.

  • Node.js 18+ installed
  • An Aether account with a connected site
  • Basic Astro knowledge
Terminal window
npm create astro@latest my-aether-site
cd my-aether-site

Choose:

  • Template: Empty
  • TypeScript: Yes (strict)
  • Install dependencies: Yes
Terminal window
# Install SDK and CLI
npm install @aether-official/sites-sdk
npm install -D @aether-official/cli

Run the interactive setup wizard:

Terminal window
npx aether-sdk init

You’ll be prompted for:

  • Site ID: Found in Aether dashboard → Sites → Your Site → Settings
  • Organization ID: Found in Aether dashboard → Organization Settings
  • API Token: Generate in Aether dashboard → Sites → Your Site → API
  • API URL: Use http://localhost:3000 for development

The CLI will:

  1. Test your connection
  2. Create .env file with your credentials
  3. Fetch your site’s schema
  4. Generate TypeScript types in src/aether-types.d.ts

Output:

Terminal window
Connected successfully!
Found 3 section templates
Created .env file
Schema saved to .aether/schema.json
Types generated: src/aether-types.d.ts
  1. Open Aether dashboard
  2. Go to SitesYour SiteVisual Editor
  3. Create a new section template (e.g., “Hero”)
  4. Add fields:
    • title (Text)
    • subtitle (Textarea)
    • cta_text (Text)
    • cta_url (Text)

After creating sections in Aether, sync to get the latest types:

Terminal window
npx aether-sdk sync && npx aether-sdk types

Create a page that fetches and displays content:

src/pages/index.astro
---
import { fetch, aether } from '@aether-official/sites-sdk/astro';
import { SECTIONS } from '../aether-types';
import { getConfig } from '@aether-official/sites-sdk/astro';
const config = getConfig(import.meta.env);
// Fetch hero section with full type safety
const hero = await fetch.section(SECTIONS.HERO, config);
// Create helper for data attributes
const helper = aether.section(SECTIONS.HERO);
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<title>My Aether Site</title>
</head>
<body>
<!-- Section wrapper with ID -->
<section {...helper.section()}>
<!-- Title field with data attribute for editing -->
<h1 {...helper.field('title')}>
{hero.data.title}
</h1>
<!-- Subtitle field -->
<p {...helper.field('subtitle')}>
{hero.data.subtitle}
</p>
<!-- CTA button -->
<a
href={hero.data.cta_url}
{...helper.field('cta_text')}
>
{hero.data.cta_text}
</a>
</section>
<!-- Initialize SDK for visual editing -->
<script>
import { AetherSDK } from '@aether-official/sites-sdk';
new AetherSDK({
siteId: import.meta.env.PUBLIC_AETHER_SITE_ID,
organizationId: import.meta.env.PUBLIC_AETHER_ORG_ID,
editorOrigin: import.meta.env.PUBLIC_AETHER_EDITOR_URL,
});
</script>
</body>
</html>
Terminal window
npm run dev

Open http://localhost:4321 - you should see your content!

  1. Open Aether dashboard → Visual Editor
  2. Enter your local URL: http://localhost:4321
  3. Click Open Editor

You can now click any field to edit it inline! Changes save to Aether and update immediately.

Type-Safe Development: Full autocomplete for all content fields ✅ Visual Editing: Content editors can edit directly on your site ✅ Hot Reload: Changes reflect instantly in development ✅ Build-Time Rendering: Content fetched at build time for optimal performance ✅ Version Control: Your code stays in Git, content in Aether

  1. Create section template in Aether visual editor
  2. Sync schema: npx aether-sdk sync && npx aether-sdk types
  3. Use in your code:
import { SECTIONS } from '../aether-types';
const newSection = await fetch.section(SECTIONS.YOUR_NEW_SECTION, config);
  1. Add fields in Aether visual editor
  2. Sync schema: npx aether-sdk sync && npx aether-sdk types
  3. TypeScript will now know about the new fields!
Terminal window
# Build your site
npm run build
# Deploy to your hosting provider
# (Vercel, Netlify, etc.)

Update environment variables on your hosting provider:

  • AETHER_SITE_ID
  • AETHER_ORGANIZATION_ID
  • AETHER_API_TOKEN
  • AETHER_API_URL → Use your production Aether URL
  • PUBLIC_AETHER_SITE_ID
  • PUBLIC_AETHER_ORG_ID
  • PUBLIC_AETHER_EDITOR_URL

Here’s a more complete page with multiple sections:

src/pages/index.astro
---
import { fetch, aether } from '@aether-official/sites-sdk/astro';
import { SECTIONS } from '../aether-types';
import { getConfig } from '@aether-official/sites-sdk/astro';
const config = getConfig(import.meta.env);
// Fetch multiple sections
const [hero, features, cta] = await Promise.all([
fetch.section(SECTIONS.HERO, config),
fetch.section(SECTIONS.FEATURES, config),
fetch.section(SECTIONS.CTA, config),
]);
const heroHelper = aether.section(SECTIONS.HERO);
const featuresHelper = aether.section(SECTIONS.FEATURES);
const ctaHelper = aether.section(SECTIONS.CTA);
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>My Site</title>
<style>
body { font-family: system-ui; max-width: 1200px; margin: 0 auto; }
section { padding: 4rem 2rem; }
.features { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2rem; }
</style>
</head>
<body>
<!-- Hero Section -->
<section {...heroHelper.section()}>
<h1 {...heroHelper.field('title', hero.data.title)}>
{hero.data.title}
</h1>
<p {...heroHelper.field('subtitle', hero.data.subtitle)}>
{hero.data.subtitle}
</p>
</section>
<!-- Features Section -->
<section {...featuresHelper.section()}>
<h2 {...featuresHelper.field('heading', features.data.heading)}>
{features.data.heading}
</h2>
<div class="features">
{features.data.items?.map((item, i) => (
<div {...featuresHelper.repeaterItem('items', i)}>
<h3 {...featuresHelper.field(`items.${i}.title`, item.title)}>
{item.title}
</h3>
<p {...featuresHelper.field(`items.${i}.description`, item.description)}>
{item.description}
</p>
</div>
))}
</div>
</section>
<!-- CTA Section -->
<section {...ctaHelper.section()}>
<h2 {...ctaHelper.field('heading', cta.data.heading)}>
{cta.data.heading}
</h2>
<a
href={cta.data.button_url}
{...ctaHelper.field('button_text', cta.data.button_text)}
>
{cta.data.button_text}
</a>
</section>
<script>
import { AetherSDK } from '@aether-official/sites-sdk';
new AetherSDK({
siteId: import.meta.env.PUBLIC_AETHER_SITE_ID,
organizationId: import.meta.env.PUBLIC_AETHER_ORG_ID,
editorOrigin: import.meta.env.PUBLIC_AETHER_EDITOR_URL,
});
</script>
</body>
</html>

Problem: Generated types don’t reflect changes made in Aether

Solution:

Terminal window
# Clear cache and regenerate
rm -rf .aether
npx aether-sdk sync && npx aether-sdk types
# Restart dev server
npm run dev

Problem: Connection failed: Unauthorized

Solution:

  • Verify API token in .env
  • Check API URL is correct
  • Ensure token hasn’t expired

Problem: Section with ID 'xyz' not found

Solution:

  • Run npx aether-sdk sync to fetch latest schema
  • Verify section ID in SECTIONS constant
  • Check section exists in Aether dashboard