DEV Community

Cover image for How to Build a Natal Chart App with Free Western Astrology API — Aspects, Houses & Synastry
AstroAsk
AstroAsk

Posted on

How to Build a Natal Chart App with Free Western Astrology API — Aspects, Houses & Synastry

Natal chart with aspects, house systems, chart patterns, synastry, and SVG wheel rendering — one API call, 75ms.


Table of Contents


The Problem

You're building a Western astrology app. Users want:

  • Natal chart (birth chart) with all 10 planets
  • Aspects between planets (conjunction, trine, square, etc.)
  • House systems (Placidus, Koch, Equal, Whole Sign)
  • Synastry (relationship compatibility)
  • Solar return (birthday chart for the year ahead)
  • A visual chart wheel they can share

You search for a Western astrology API and find:

  • APIs that only do Vedic astrology
  • APIs that need 10+ separate calls for one complete chart
  • APIs that charge per-endpoint (one call for planets, another for houses, another for aspects...)
  • APIs with no SVG rendering — you have to build your own chart wheel
  • APIs that cost $37-850/month before you even test

What if one API returned everything in a single call?


Meet AstroAsk — Free Western Astrology API

AstroAsk is a free API built specifically for developers adding astrology to their apps.

Why developers love it:

  • ✅ Complete natal chart in one API call
  • ✅ 10 planets + 12 houses + all major aspects
  • ✅ Multiple house systems (Placidus, Koch, Equal, Whole Sign, more)
  • ✅ Chart pattern detection (Grand Trine, Grand Cross, T-Square, Yod, Stellium)
  • ✅ Synastry for relationship compatibility
  • ✅ Solar return charts
  • ✅ Secondary progressions & solar arc directions
  • ✅ Planetary transits to natal chart
  • ✅ SVG chart wheel rendering (ready to display)
  • ✅ Auto-timezone from coordinates (no UTC conversion!)
  • ✅ 75ms average latency
  • ✅ Free tier: 500 requests/month
  • ✅ NASA JPL-precision calculations

What We're Building

A complete Western astrology feature that:

  1. Takes birth details (date, time, place)
  2. Returns natal chart with planets, houses, and aspects
  3. Detects chart patterns (Grand Trine, T-Square, Yod)
  4. Calculates synastry between two people
  5. Generates solar return for any year
  6. Renders as a beautiful SVG chart wheel

Time to build: 10 minutes


Step 1: Get Your Free API Key

  1. Go to AstroAsk on RapidAPI
  2. Click "Subscribe to Test"
  3. Select the Basic (Free) plan
  4. Copy your API key from the dashboard

No credit card needed.


Step 2: Your First Natal Chart API Call

Let's get a Western natal chart for someone born on November 11, 2002 at midnight in New York.

Python

import requests

url = "https://astroask-vedic-western-astrology-api.p.rapidapi.com/api/v1/western"

payload = {
    "date": "2002-11-11T00:00:00",
    "lat": 40.7128,   # New York latitude
    "lng": -74.0060,  # New York longitude
    "houseSystem": "placidus",
    "format": "json"
}

headers = {
    "x-rapidapi-key": "YOUR_API_KEY",
    "x-rapidapi-host": "astroask-vedic-western-astrology-api.p.rapidapi.com",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)
data = response.json()

print(data)
Enter fullscreen mode Exit fullscreen mode

JavaScript (Node.js)

const url = "https://astroask-vedic-western-astrology-api.p.rapidapi.com/api/v1/western";

const payload = {
    date: "2002-11-11T00:00:00",
    lat: 40.7128,
    lng: -74.0060,
    houseSystem: "placidus",
    format: "json"
};

const response = await fetch(url, {
    method: "POST",
    headers: {
        "x-rapidapi-key": "YOUR_API_KEY",
        "x-rapidapi-host": "astroask-vedic-western-astrology-api.p.rapidapi.com",
        "Content-Type": "application/json"
    },
    body: JSON.stringify(payload)
});

const data = await response.json();
console.log(data);
Enter fullscreen mode Exit fullscreen mode

cURL

curl -X POST "https://astroask-vedic-western-astrology-api.p.rapidapi.com/api/v1/western" \
  -H "x-rapidapi-key: YOUR_API_KEY" \
  -H "x-rapidapi-host: astroask-vedic-western-astrology-api.p.rapidapi.com" \
  -H "Content-Type: application/json" \
  -d '{"date": "2002-11-11T00:00:00", "lat": 40.7128, "lng": -74.0060, "houseSystem": "placidus"}'
Enter fullscreen mode Exit fullscreen mode

Step 3: Understanding the Natal Chart Response

Here's what you get back:

{
  "success": true,
  "data": {
    "planets": [
      {
        "planet": "Sun",
        "signName": "Scorpio",
        "tropicalLongitude": 228.19,
        "house": 3,
        "isRetrograde": false
      },
      {
        "planet": "Moon",
        "signName": "Aquarius",
        "tropicalLongitude": 305.41,
        "house": 6,
        "isRetrograde": false
      },
      {
        "planet": "Mercury",
        "signName": "Scorpio",
        "tropicalLongitude": 215.87,
        "house": 3,
        "isRetrograde": false
      }
      // ... all 10 planets (Sun through Pluto)
    ],
    "houses": {
      "houses": [
        {"house": 1, "sign": "Libra", "cusp": 195.52},
        {"house": 2, "sign": "Scorpio", "cusp": 225.31}
        // ... all 12 houses
      ],
      "ascendant": {"sign": "Libra", "degree": 15.52},
      "midheaven": {"sign": "Cancer", "degree": 78.23}
    },
    "aspects": [
      {
        "planet1": "Sun",
        "planet2": "Moon",
        "aspect": "Square",
        "angle": 82.78,
        "orb": 7.22,
        "isApplying": true
      },
      {
        "planet1": "Venus",
        "planet2": "Mars",
        "aspect": "Trine",
        "angle": 119.45,
        "orb": 0.55,
        "isApplying": false
      }
      // ... all major aspects
    ],
    "patterns": [
      {
        "type": "Stellium",
        "planets": ["Sun", "Mercury", "Venus"],
        "sign": "Scorpio",
        "description": "3 planets in Scorpio — intense focus on transformation"
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

Key Western fields:

Field What it means
planets All 10 planets with tropical zodiac positions
houses 12 house cusps with signs (Placidus system)
aspects Angles between planets (conjunction, trine, square, etc.)
patterns Detected chart shapes (Grand Trine, T-Square, Yod, Stellium)
ascendant Rising sign — your public persona
midheaven Career and reputation point

Step 4: Aspects — The Hidden Language of Charts

Aspects are the angles between planets. They reveal how planetary energies interact.

The Major Aspects:

Aspect Angle Symbol Meaning
Conjunction Energies merge — intense focus
Sextile 60° Easy flow — opportunities
Square 90° Tension — growth through challenge
Trine 120° Harmony — natural talent
Opposition 180° Polarity — awareness through contrast

The Minor Aspects:

Aspect Angle Meaning
Semi-sextile 30° Subtle connection
Quincunx 150° Adjustment needed
Semi-square 45° Mild friction
Sesquiquadrate 135° Inner tension

Using aspects in your app:

def get_chart_aspects(birth_data):
    """Get all aspects in a natal chart."""
    chart = get_natal_chart(birth_data)
    aspects = chart['aspects']

    # Filter for major aspects only
    major_aspects = [a for a in aspects if a['aspect'] in 
        ['Conjunction', 'Trine', 'Square', 'Sextile', 'Opposition']]

    # Sort by orb (tightest aspects first — most powerful)
    major_aspects.sort(key=lambda a: a['orb'])

    return {
        "total_aspects": len(aspects),
        "major_aspects": major_aspects,
        "tightest_aspect": major_aspects[0] if major_aspects else None
    }
Enter fullscreen mode Exit fullscreen mode

Why orb matters:

The "orb" is how far off the exact angle the aspect is. Tighter orb = stronger influence.

  • 0-2°: Very strong — dominant influence
  • 2-5°: Strong — clearly felt
  • 5-8°: Moderate — noticeable
  • 8-10°: Weak — background influence

Step 5: House Systems Explained

Houses divide the chart into 12 life areas. Different house systems calculate house cusps differently.

Supported house systems:

System Best for How it works
Placidus Most popular Time-based division (default)
Koch German tradition Birth time sensitive
Equal Simple Each house = 30°
Whole Sign Modern revival Each sign = one house
Campanus Space-based Prime vertical division
Regiomontanus Medieval Celestial equator based

Switching house systems:

# Default — Placidus
payload = {"date": "2002-11-11T00:00:00", "lat": 40.7128, "lng": -74.0060}

# Explicit house system
payload = {
    "date": "2002-11-11T00:00:00",
    "lat": 40.7128,
    "lng": -74.0060,
    "houseSystem": "whole_sign"  # Options: placidus, koch, equal, whole_sign, campanus, regiomontanus
}
Enter fullscreen mode Exit fullscreen mode

The 12 Houses:

House Life Area Keywords
1st Self Identity, appearance, first impressions
2nd Values Money, possessions, self-worth
3rd Communication Siblings, short travel, learning
4th Home Family, roots, private life
5th Creativity Romance, children, hobbies
6th Health Daily routine, work, service
7th Partnerships Marriage, open enemies, contracts
8th Transformation Death, taxes, shared resources
9th Philosophy Higher education, travel, beliefs
10th Career Reputation, authority, public image
11th Community Friends, hopes, social causes
12th Subconscious Secrets, isolation, spiritual growth

Step 6: Chart Patterns (Grand Trine, T-Square, Yod)

The API automatically detects major chart patterns. These are rare configurations that shape personality.

Supported patterns:

Pattern Shape Meaning
Grand Trine △△△ (3 trines) Natural talent — things come easy
Grand Cross □□□□ (4 squares) Intense challenges — builds resilience
T-Square □△ (2 squares + opposition) Driven tension — motivates achievement
Yod ⚹⚹△ (2 sextiles + quincunx) "Finger of God" — special mission
Stellium 3+ planets in one sign Intense focus in one life area

Detecting patterns:

def analyze_chart_patterns(birth_data):
    """Detect major chart patterns in a natal chart."""
    chart = get_natal_chart(birth_data)
    patterns = chart['patterns']

    result = {
        "has_grand_trine": any(p['type'] == 'Grand Trine' for p in patterns),
        "has_t_square": any(p['type'] == 'T-Square' for p in patterns),
        "has_yod": any(p['type'] == 'Yod' for p in patterns),
        "has_stellium": any(p['type'] == 'Stellium' for p in patterns),
        "pattern_count": len(patterns),
        "patterns": patterns
    }

    if result['has_grand_trine']:
        result['advice'] = "You have natural gifts — focus on developing them"
    elif result['has_t_square']:
        result['advice'] = "Your challenges drive your greatest growth"

    return result
Enter fullscreen mode Exit fullscreen mode

You can also detect specific patterns individually:

# For detailed pattern analysis, use the patterns endpoint
url = "https://astroask-vedic-western-astrology-api.p.rapidapi.com/api/v1/western/patterns"

payload = {"date": "2002-11-11T00:00:00"}

response = requests.post(url, json=payload, headers=headers)
patterns = response.json()

# Returns: grandTrines, grandCrosses, tSquares, yods, stelliums
print(f"Grand Trines: {patterns['data']['summary']['grandTrineCount']}")
print(f"T-Squares: {patterns['data']['summary']['tSquareCount']}")
Enter fullscreen mode Exit fullscreen mode

Step 7: Synastry — Relationship Compatibility

Synastry compares two birth charts to reveal relationship dynamics. Different from Vedic Gun Milan — this is the Western approach.

API call for synastry:

url = "https://astroask-vedic-western-astrology-api.p.rapidapi.com/api/v1/compatibility"

payload = {
    "person1": {
        "date": "2002-11-11T00:00:00",
        "lat": 40.7128,
        "lng": -74.0060
    },
    "person2": {
        "date": "1999-05-15T14:30:00",
        "lat": 34.0522,
        "lng": -118.2437
    },
    "system": "western"  # Key: use "western" for tropical synastry
}

response = requests.post(url, json=payload, headers=headers)
synastry = response.json()

print(synastry)
Enter fullscreen mode Exit fullscreen mode

What synastry reveals:

def get_relationship_report(person1_data, person2_data):
    """Generate a Western synastry compatibility report."""
    synastry = get_synastry(person1_data, person2_data, system="western")

    # Find the strongest aspects between charts
    interaspects = synastry['data']['interaspects']

    # Categorize by type
    harmonious = [a for a in interaspects if a['aspect'] in ['Trine', 'Sextile', 'Conjunction']]
    challenging = [a for a in interaspects if a['aspect'] in ['Square', 'Opposition']]

    return {
        "harmonious_connections": len(harmonious),
        "challenging_connections": len(challenging),
        "strongest_aspect": min(interaspects, key=lambda a: a['orb']),
        "summary": generate_summary(harmonious, challenging)
    }
Enter fullscreen mode Exit fullscreen mode

Key synastry aspects to look for:

Cross-Aspect Meaning
Sun-Moon conjunction Core compatibility — emotional understanding
Venus-Mars conjunction Romantic chemistry — strong attraction
Moon-Moon trine Emotional flow — feel at home together
Sun-Saturn square Growth through friction — builds commitment
Venus-Venus trine Shared values — easy affection

Step 8: Solar Return — Your Year Ahead

A solar return chart is cast for the exact moment the Sun returns to its natal position each year. It reveals themes for the year ahead.

url = "https://astroask-vedic-western-astrology-api.p.rapidapi.com/api/v1/western/solar-return"

payload = {
    "date": "2002-11-11T00:00:00",  # Birth date
    "lat": 40.7128,
    "lng": -74.0060,
    "targetYear": 2026  # Which year to calculate
}

response = requests.post(url, json=payload, headers=headers)
solar_return = response.json()

print(f"Solar Return 2026 themes:")
print(f"  Ascendant: {solar_return['data']['ascendant']['sign']}")
print(f"  Sun house: {solar_return['data']['sunHouse']}")
print(f"  Moon sign: {solar_return['data']['moonSign']}")
Enter fullscreen mode Exit fullscreen mode

Why solar returns matter:

  • The solar return Ascendant shows the "face" of your year
  • The house the Sun falls in shows the year's focus area
  • Aspects in the solar return show the year's opportunities and challenges

Step 9: Display the Chart Wheel (SVG)

The API can return a beautiful SVG chart wheel ready to display. No chart-building code needed.

# Get the chart as SVG
payload = {
    "date": "2002-11-11T00:00:00",
    "lat": 40.7128,
    "lng": -74.0060,
    "format": "svg",           # Return SVG instead of JSON
    "theme": "dark",           # "light" or "dark"
    "showTable": true,         # Show planet positions table
    "width": 800,
    "height": 800,
    "wheelSize": 600,
    "rotateToAscendant": true, # Ascendant at 9 o'clock
    "planetRenderMode": "glyph",  # "glyph" (symbols) or "text"
    "signRenderMode": "glyph"     # "glyph" (symbols) or "text"
}

response = requests.post(url, json=payload, headers=headers)
svg_data = response.json()

# Save the SVG
with open("natal_chart.svg", "w") as f:
    f.write(svg_data['data']['svg'])
Enter fullscreen mode Exit fullscreen mode

HTML

<div id="natal-chart"></div>

<script>
// After fetching the API response
const chartSvg = data.data.svg;
document.getElementById('natal-chart').innerHTML = chartSvg;
</script>
Enter fullscreen mode Exit fullscreen mode

React

function NatalChart({ birthData }) {
  const [chartSvg, setChartSvg] = useState('');

  useEffect(() => {
    fetch('/api/western', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ ...birthData, format: 'svg', theme: 'dark' })
    })
    .then(res => res.json())
    .then(data => setChartSvg(data.data.svg));
  }, [birthData]);

  return (
    <div 
      className="natal-chart-container"
      dangerouslySetInnerHTML={{ __html: chartSvg }} 
    />
  );
}
Enter fullscreen mode Exit fullscreen mode

SVG customization options:

Option Values Default
theme light, dark light
showTable true, false false
width pixels 800
height pixels 800
wheelSize pixels 600
layout row, column row
planetRenderMode glyph, text glyph
signRenderMode glyph, text glyph
fillZodiacElements true, false false

Real-World Use Cases

1. Astrology Dating App

@app.route('/api/compatibility-check')
def compatibility_check():
    """Check synastry between two users."""
    synastry = get_synastry(
        user1.birth_data, 
        user2.birth_data, 
        system="western"
    )

    interaspects = synastry['data']['interaspects']

    # Calculate compatibility score
    harmonious = len([a for a in interaspects if a['aspect'] in ['Trine', 'Sextile']])
    challenging = len([a for a in interaspects if a['aspect'] in ['Square', 'Opposition']])

    score = min(100, max(0, 50 + (harmonious * 10) - (challenging * 5)))

    return {
        "compatibility_score": score,
        "harmonious_aspects": harmonious,
        "challenging_aspects": challenging,
        "strongest_connection": min(interaspects, key=lambda a: a['orb']),
        "summary": generate_synastry_summary(interaspects)
    }
Enter fullscreen mode Exit fullscreen mode

2. Daily Horoscope Generator

@app.route('/api/daily-horoscope')
def daily_horoscope():
    """Generate personalized daily horoscope using transits."""
    # Get current transits to user's natal chart
    transits = get_transits(user.birth_data, target_date=today)

    # Find active transits (tight orbs)
    active_transits = [t for t in transits if t['orb'] < 3]

    prompt = f"""
    User's natal chart: {user.birth_chart}
    Active transits today: {active_transits}

    Write a personalized daily horoscope based on these transits.
    Be specific about which planetary aspects are active.
    """

    return {"horoscope": ai_generate(prompt)}
Enter fullscreen mode Exit fullscreen mode

3. Year-Ahead Report

@app.route('/api/year-ahead')
def year_ahead():
    """Generate solar return + progressions report."""
    solar_return = get_solar_return(user.birth_data, target_year=2026)
    progressions = get_progressions(user.birth_data, target_date=today)

    return {
        "solar_return": {
            "themes": solar_return['data']['themes'],
            "focus_area": solar_return['data']['sunHouse'],
            "opportunities": solar_return['data']['aspects']
        },
        "progressions": {
            "progressed_moon_sign": progressions['data']['progressedMoonSign'],
            "solar_arc_aspects": progressions['data']['solarArcAspects']
        },
        "advice": generate_year_advice(solar_return, progressions)
    }
Enter fullscreen mode Exit fullscreen mode

4. Embeddable Chart Widget

// Embed natal chart in any website
function embedChart(containerId, birthData, options = {}) {
  const defaultOptions = {
    format: 'svg',
    theme: 'dark',
    width: 500,
    height: 500,
    wheelSize: 400,
    showTable: true,
    rotateToAscendant: true
  };

  const payload = { ...birthData, ...defaultOptions, ...options };

  fetch('https://astroask-vedic-western-astrology-api.p.rapidapi.com/api/v1/western', {
    method: 'POST',
    headers: {
      'x-rapidapi-key': 'YOUR_API_KEY',
      'x-rapidapi-host': 'astroask-vedic-western-astrology-api.p.rapidapi.com',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(payload)
  })
  .then(res => res.json())
  .then(data => {
    document.getElementById(containerId).innerHTML = data.data.svg;
  });
}

// Usage
embedChart('my-chart', {
  date: '2002-11-11T00:00:00',
  lat: 40.7128,
  lng: -74.0060
}, { theme: 'dark', width: 600 });
Enter fullscreen mode Exit fullscreen mode

Gotchas & Tips

1. Timezone Handling

Don't convert to UTC! The API auto-derives timezone from coordinates.

# ✅ CORRECT — use local birth time
{"date": "2002-11-11T14:30:00", "lat": 40.7128, "lng": -74.0060}

# ❌ WRONG — don't convert to UTC yourself
{"date": "2002-11-11T19:30:00Z", "lat": 40.7128, "lng": -74.0060}
Enter fullscreen mode Exit fullscreen mode

2. Tropical vs Sidereal Zodiac

AstroAsk Western API uses tropical zodiac (Western standard). If you need sidereal (Vedic), use the /api/v1/kundali endpoint instead.

# Western — tropical zodiac (Aries starts at vernal equinox)
response = requests.post(".../api/v1/western", ...)

# Vedic — sidereal zodiac (accounts for precession)
response = requests.post(".../api/v1/kundali", ...)
Enter fullscreen mode Exit fullscreen mode

3. House System Selection

Different astrologers prefer different house systems. Let users choose:

HOUSE_SYSTEMS = {
    "placidus": "Most popular (default)",
    "koch": "German school",
    "equal": "Simple 30° houses",
    "whole_sign": "Modern revival — each sign = one house",
    "campanus": "Space-based division",
    "regiomontanus": "Medieval tradition"
}
Enter fullscreen mode Exit fullscreen mode

4. Coordinate Accuracy

For accurate house cusps, use precise coordinates:

# ❌ WRONG — city center approximation
{"lat": 40.7, "lng": -74.0}

# ✅ CORRECT — precise coordinates
{"lat": 40.7128, "lng": -74.0060}
Enter fullscreen mode Exit fullscreen mode

House cusps are sensitive to location. A 0.1° difference in coordinates can shift house boundaries.

5. Rate Limiting

Free tier: 500 requests/month. Cache results!

from functools import lru_cache

@lru_cache(maxsize=1000)
def get_natal_chart(date, lat, lng):
    # Only calls API once per unique birth data
    return api_call(date, lat, lng)
Enter fullscreen mode Exit fullscreen mode

6. Aspect Orbs

The API returns aspects with their orb (distance from exact angle). Filter for tight orbs for strongest influences:

# Get only strong aspects (orb < 5°)
strong_aspects = [a for a in aspects if a['orb'] < 5]
Enter fullscreen mode Exit fullscreen mode

7. Error Handling

Always check for errors:

response = requests.post(url, json=payload, headers=headers)
data = response.json()

if not data.get('success'):
    error = data.get('error', 'Unknown error')
    print(f"API Error: {error}")
    return None
Enter fullscreen mode Exit fullscreen mode

What to Build Next

Now that you have the basics, here are ideas:

  1. Astrology Dating App — Synastry-based matching
  2. Daily Horoscope Newsletter — Transits to natal chart
  3. Birth Chart Generator — Shareable SVG chart wheels
  4. Year-Ahead Reports — Solar return + progressions
  5. Compatibility Calculator — Relationship analysis widget
  6. Astrology Chatbot — AI-powered chart interpretation
  7. Transit Tracker — "What's affecting you today"
  8. Chart Pattern Finder — "Do you have a Grand Trine?"

Links & Resources


Conclusion

Building a Western astrology app doesn't have to be hard. With AstroAsk:

  • One API call gets you planets, houses, aspects, and patterns
  • SVG rendering means no chart-wheel building code
  • Multiple house systems serve all astrologer preferences
  • Synastry powers dating and compatibility apps
  • Free tier lets you test without commitment
  • 75ms latency keeps your app fast

Try it today. Your users will thank you.


Have questions? Drop a comment below or email us at intelligence@astroask.app


About the Author
Building AstroAsk — making astrology accessible to developers. NASA JPL-precision calculations, tropical + sidereal zodiac, one API.

Top comments (0)