How to Build a Kundli Generator App in React Native (Complete Tutorial)

10 min read
Brajesh Vashisht
Vedic AstrologyReact NativeKundali GeneratorBirth ChartMobile App Development

Complete step-by-step guide to building a Janam Kundali app with birth chart calculations, planetary positions, and Rashi visualization using RoxyAPI.

TL;DR

  • Build a production-ready Kundli (Janam Kundali) generator with React Native and the RoxyAPI Vedic Astrology API
  • The TypeScript SDK (@roxyapi/sdk) handles authentication, types, and response parsing automatically
  • One API call returns all 9 grahas, Lagna, nakshatras, house descriptions, combustion, and planetary war data
  • Get started in 30 minutes: install the SDK, collect birth details, display the chart

About the author: Brajesh Vashisht is a Vedic Astrologer and KP Systems Specialist with 22 years of experience in Vedic astrology and Krishnamurti Paddhati. He holds a postgraduate degree in Jyotish Shastra from Banaras Hindu University and has authored two books on KP sub-lord theory and nakshatra analysis.

Building a Kundli generator app requires precise sidereal planetary calculations, proper nakshatra mapping, and accurate house cusp determination. Most mobile developers lack the astronomical math to compute Lahiri ayanamsa corrections or Vimshottari dasha periods from scratch. The RoxyAPI Vedic Astrology API solves this by returning a complete Janam Kundali birth chart, verified against NASA JPL Horizons data, in a single POST request. This tutorial walks you through building a Kundli generator in React Native using the official TypeScript SDK.

What you will build with the Vedic Astrology API

Your Kundli generator app will collect birth details (date, time, location) and display a complete Vedic birth chart. The API returns all 9 Navagraha positions (Sun, Moon, Mars, Mercury, Jupiter, Venus, Saturn, Rahu, Ketu) plus the Lagna (Ascendant), each with their rashi, sidereal longitude, nakshatra name, and pada.

It also returns 12 bhava (house) descriptions, combustion detection for planets near the Sun, and planetary war data when two grahas fall within one degree of each other. The response includes an interpretations object with per-planet rashi and nakshatra readings, so your app can display meaningful Jyotish content without maintaining a separate interpretation database. All positions use the Lahiri ayanamsa and are cross-referenced against 828 gold standard test cases from DrikPanchang and onlinejyotish.

Ready to build this? RoxyAPI Vedic Astrology API gives you 40+ Vedic astrology endpoints with a single API key. See pricing.

How to set up the project and install the SDK

Initialize your Expo project and install the RoxyAPI TypeScript SDK. The SDK provides full TypeScript types for every endpoint, so you do not need to write manual interface definitions.

npx create-expo-app kundli-generator
cd kundli-generator

npm install @roxyapi/sdk
npm install @react-navigation/native @react-navigation/stack
npm install @react-native-async-storage/async-storage
npx expo install react-native-screens react-native-safe-area-context

Create your API client in a single line:

// lib/roxy.ts
import { createRoxy } from '@roxyapi/sdk';

export const roxy = createRoxy(process.env.EXPO_PUBLIC_ROXY_API_KEY!);

The SDK configures the base URL, authentication headers, and response typing automatically. Compare this to the alternative: manually defining 80+ lines of TypeScript interfaces and constructing raw fetch calls with error handling. Store your API key in .env as EXPO_PUBLIC_ROXY_API_KEY and never commit it to source control.

How to build the birth details input form

The birth chart endpoint requires five fields: date (YYYY-MM-DD), time (HH:MM:SS, 24-hour format), latitude, longitude, and timezone (UTC offset as a decimal number, defaulting to 5.5 for IST). Here is the core form and API call logic:

// screens/BirthDetailsScreen.tsx
import React, { useState } from 'react';
import {
  View, Text, TextInput, TouchableOpacity,
  ScrollView, ActivityIndicator, StyleSheet, Platform,
} from 'react-native';
import DateTimePicker from '@react-native-community/datetimepicker';
import { roxy } from '../lib/roxy';

export function BirthDetailsScreen({ navigation }: any) {
  const [date, setDate] = useState(new Date(1990, 6, 15));
  const [time, setTime] = useState(new Date(1990, 6, 15, 14, 30));
  const [latitude, setLatitude] = useState('28.6139');
  const [longitude, setLongitude] = useState('77.2090');
  const [timezone, setTimezone] = useState('5.5');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [showDatePicker, setShowDatePicker] = useState(false);
  const [showTimePicker, setShowTimePicker] = useState(false);

  const formatDate = (d: Date) => {
    const y = d.getFullYear();
    const m = String(d.getMonth() + 1).padStart(2, '0');
    const day = String(d.getDate()).padStart(2, '0');
    return `${y}-${m}-${day}`;
  };

  const formatTime = (d: Date) => {
    const h = String(d.getHours()).padStart(2, '0');
    const m = String(d.getMinutes()).padStart(2, '0');
    return `${h}:${m}:00`;
  };

  const handleSubmit = async () => {
    setLoading(true);
    setError(null);

    const { data, error: apiError } = await roxy.vedicAstrology.generateBirthChart({
      body: {
        date: formatDate(date),
        time: formatTime(time),
        latitude: parseFloat(latitude),
        longitude: parseFloat(longitude),
        timezone: parseFloat(timezone),
      },
    });

    setLoading(false);

    if (apiError) {
      setError('Failed to generate Kundli. Please check your inputs.');
      return;
    }

    navigation.navigate('Chart', { chart: data });
  };

  return (
    <ScrollView style={styles.container}>
      <Text style={styles.title}>Generate Janam Kundali</Text>
      <Text style={styles.subtitle}>
        Enter accurate birth details for precise Vedic astrology calculations
      </Text>

      <TouchableOpacity style={styles.dateButton} onPress={() => setShowDatePicker(true)}>
        <Text>Birth Date: {formatDate(date)}</Text>
      </TouchableOpacity>
      {showDatePicker && (
        <DateTimePicker
          value={date} mode="date" maximumDate={new Date()}
          onChange={(_, d) => { setShowDatePicker(Platform.OS === 'ios'); if (d) setDate(d); }}
        />
      )}

      <TouchableOpacity style={styles.dateButton} onPress={() => setShowTimePicker(true)}>
        <Text>Birth Time: {formatTime(time)}</Text>
      </TouchableOpacity>
      {showTimePicker && (
        <DateTimePicker
          value={time} mode="time" is24Hour
          onChange={(_, t) => { setShowTimePicker(Platform.OS === 'ios'); if (t) setTime(t); }}
        />
      )}

      <TextInput placeholder="Latitude (28.6139)" value={latitude}
        onChangeText={setLatitude} keyboardType="numeric" style={styles.input} />
      <TextInput placeholder="Longitude (77.2090)" value={longitude}
        onChangeText={setLongitude} keyboardType="numeric" style={styles.input} />
      <TextInput placeholder="Timezone: 5.5 for IST" value={timezone}
        onChangeText={setTimezone} keyboardType="numeric" style={styles.input} />

      {error && <Text style={styles.error}>{error}</Text>}

      <TouchableOpacity style={styles.button} onPress={handleSubmit} disabled={loading}>
        {loading ? <ActivityIndicator color="#fff" /> : <Text style={styles.buttonText}>Generate Kundli</Text>}
      </TouchableOpacity>
    </ScrollView>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, padding: 20, paddingTop: 60, backgroundColor: '#FFF8F0' },
  title: { fontSize: 28, fontWeight: 'bold', color: '#8B4513', textAlign: 'center', marginBottom: 8 },
  subtitle: { fontSize: 14, color: '#A0522D', textAlign: 'center', marginBottom: 32 },
  input: { borderWidth: 2, borderColor: '#F4A460', borderRadius: 12, padding: 14, marginBottom: 16, backgroundColor: '#fff' },
  dateButton: { borderWidth: 2, borderColor: '#F4A460', borderRadius: 12, padding: 14, marginBottom: 16, backgroundColor: '#fff' },
  error: { color: '#D2691E', textAlign: 'center', marginBottom: 12 },
  button: { backgroundColor: '#CD853F', borderRadius: 12, padding: 16, alignItems: 'center' },
  buttonText: { color: '#fff', fontSize: 16, fontWeight: '600' },
});

The SDK method roxy.vedicAstrology.generateBirthChart() accepts a body object with the birth parameters and returns a typed { data, error } result. No manual JSON parsing or HTTP status code handling is needed.

How to display the Kundli with planetary positions

The API response includes a meta object for quick planet lookup by name, 12 rashi house objects with planet arrays, and a houses array with bhava descriptions. Here is the chart display screen:

// screens/ChartScreen.tsx
import React from 'react';
import { ScrollView, View, Text, StyleSheet } from 'react-native';

function formatDegrees(longitude: number): string {
  const inSign = longitude % 30;
  const deg = Math.floor(inSign);
  const min = Math.floor((inSign - deg) * 60);
  return `${deg}d ${min}m`;
}

export function ChartScreen({ route }: any) {
  const { chart } = route.params;
  const planets = Object.values(chart.meta) as any[];

  return (
    <ScrollView style={styles.container}>
      <View style={styles.lagnaCard}>
        <Text style={styles.lagnaTitle}>Lagna (Ascendant)</Text>
        <Text style={styles.lagnaRashi}>{chart.meta.Lagna.rashi}</Text>
        <Text>{chart.meta.Lagna.nakshatra.name} (Pada {chart.meta.Lagna.nakshatra.pada})</Text>
        <Text style={styles.mono}>{formatDegrees(chart.meta.Lagna.longitude)}</Text>
      </View>

      <Text style={styles.sectionTitle}>Planetary Positions (Navagraha)</Text>
      {planets
        .filter((p) => p.graha !== 'Lagna')
        .map((planet) => (
          <View key={planet.graha} style={styles.card}>
            <View style={styles.row}>
              <Text style={styles.planetName}>
                {planet.graha}{planet.isRetrograde ? ' (R)' : ''}
              </Text>
              <Text style={styles.rashi}>{planet.rashi}</Text>
            </View>
            <Text>{planet.nakshatra.name} Pada {planet.nakshatra.pada}</Text>
            <Text style={styles.mono}>{formatDegrees(planet.longitude)}</Text>
          </View>
        ))}

      {chart.combustion.length > 0 && (
        <>
          <Text style={styles.sectionTitle}>Combustion</Text>
          {chart.combustion.map((c: any) => (
            <View key={c.planet} style={styles.card}>
              <Text>{c.planet}: {c.distanceFromSun.toFixed(1)} degrees from Sun (orb: {c.orb})</Text>
            </View>
          ))}
        </>
      )}

      <Text style={styles.sectionTitle}>Twelve Houses (Bhavas)</Text>
      {chart.houses.map((house: any) => (
        <View key={house.number} style={styles.card}>
          <Text style={styles.planetName}>{house.number}. {house.name}</Text>
          <Text>{house.description}</Text>
        </View>
      ))}
    </ScrollView>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, padding: 16, backgroundColor: '#FFF8F0' },
  lagnaCard: { backgroundColor: '#fff', borderRadius: 16, padding: 20, alignItems: 'center', marginBottom: 24 },
  lagnaTitle: { fontSize: 14, color: '#A0522D', marginBottom: 4 },
  lagnaRashi: { fontSize: 28, fontWeight: 'bold', color: '#CD853F', marginBottom: 8 },
  sectionTitle: { fontSize: 20, fontWeight: 'bold', color: '#8B4513', marginBottom: 16, marginTop: 8 },
  card: { backgroundColor: '#fff', borderRadius: 12, padding: 16, marginBottom: 12 },
  row: { flexDirection: 'row', justifyContent: 'space-between', marginBottom: 4 },
  planetName: { fontSize: 16, fontWeight: 'bold', color: '#8B4513' },
  rashi: { fontSize: 16, fontWeight: '600', color: '#CD853F' },
  mono: { fontFamily: 'monospace', fontSize: 13, color: '#A0522D', marginTop: 4 },
});

Each rashi house (aries through pisces) contains a signs array of planets in that house. The combustion array flags planets too close to the Sun using Surya Siddhanta orb values, and planetaryWar detects planets within one degree. These features are unique to RoxyAPI and save you from implementing classical Jyotish rules manually.

How the birth chart API response is structured

Here is a real response from the birth chart endpoint for a birth in Delhi on July 15, 1990 at 14:30 IST:

{
  "aries": {
    "rashi": "aries",
    "signs": [
      {
        "graha": "Mars",
        "nakshatra": { "name": "Ashwini", "pada": 3, "key": 1 },
        "longitude": 8.15,
        "isRetrograde": false
      }
    ]
  },
  "meta": {
    "Sun": {
      "graha": "Sun",
      "rashi": "Gemini",
      "longitude": 88.92,
      "nakshatra": { "name": "Punarvasu", "pada": 3, "key": 7 },
      "isRetrograde": false
    },
    "Lagna": {
      "graha": "Lagna",
      "rashi": "Libra",
      "longitude": 198.45,
      "nakshatra": { "name": "Swati", "pada": 2, "key": 15 }
    }
  },
  "houses": [
    { "number": 1, "name": "Lagna", "description": "The first house represents self, appearance..." }
  ],
  "combustion": [
    { "planet": "Mercury", "distanceFromSun": 4.2, "orb": 14 }
  ],
  "planetaryWar": [],
  "interpretations": {
    "Sun": {
      "rashi": "Sun in Gemini brings intellectual curiosity and versatile communication...",
      "nakshatra": "Punarvasu nakshatra gives a sense of renewal and optimism..."
    }
  }
}

The interpretations field provides ready-to-display text for each planet covering both rashi placement and nakshatra influence. Your app can show meaningful Vedic astrology readings without maintaining a separate content database.

How to test the endpoint with curl

Use this curl command to verify the API response before wiring it into your app:

curl -X POST https://roxyapi.com/api/v2/vedic-astrology/birth-chart \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "date": "1990-07-15",
    "time": "14:30:00",
    "latitude": 28.6139,
    "longitude": 77.2090,
    "timezone": 5.5
  }'

Replace YOUR_API_KEY with your RoxyAPI key. Get a key at roxyapi.com/pricing and test endpoints live in the Vedic Astrology API reference.

Frequently Asked Questions

Q: What fields does the Vedic Astrology birth chart endpoint require? A: The endpoint requires date (YYYY-MM-DD), time (HH:MM:SS in 24-hour format), latitude (-90 to 90), and longitude (-180 to 180). The timezone field is optional and defaults to 5.5 (IST). All fields are simple numbers or strings with no nested objects.

Q: Does the API use tropical or sidereal zodiac calculations? A: All positions are sidereal using the Lahiri ayanamsa, which is the Indian government standard for Vedic astrology (Jyotish). Planetary longitudes are verified against NASA JPL Horizons data with sub-arc-second precision.

Q: Can I get Navamsa and other divisional charts from the same API? A: Yes. The Vedic Astrology API provides separate endpoints for Navamsa (D9) and all divisional charts from D2 through D60. Use roxy.vedicAstrology.generateNavamsa() or roxy.vedicAstrology.generateDivisionalChart() with the SDK.

Q: What other Vedic astrology features does the API offer? A: Beyond birth charts, the API covers Vimshottari dasha periods, Gun Milan (36-point compatibility), Manglik and Kalsarpa dosha detection, Shadbala strength analysis, Ashtakavarga scoring, Panchang, transits, and KP (Krishnamurti Paddhati) charts. Over 40 endpoints are available under a single API key.

Q: Is the RoxyAPI Vedic Astrology API free to use? A: RoxyAPI offers a Starter plan to begin building. All plans include every domain (Vedic astrology, Western astrology, tarot, numerology, dreams, and more) with one API key and one subscription. Check current pricing for plan details.

Conclusion

You now have a working Kundli generator app with accurate Vedic astrology calculations powered by the RoxyAPI Vedic Astrology API. The TypeScript SDK eliminates manual type definitions and raw HTTP logic, letting you focus on the user experience. Extend your app with dasha timelines, Gun Milan compatibility, dosha detection, and transit analysis, all available under the same API key.

Start building at RoxyAPI Vedic Astrology API or explore the full Vedic Astrology API reference.