Menu

  1. Docs
  2. What To Build
  3. Dating Compatibility App

Build a Dating Compatibility App

In this tutorial you will build a zodiac compatibility checker that takes two people's birth data and shows how compatible they are. One HTML file, no build tools, no frameworks.

What you will build

  • Two forms for birth data (date, time, city)
  • A compatibility score (0-100) with category breakdowns
  • Strengths and challenges of the relationship in plain English

The complete code

Create a file called compatibility.html and paste this entire block:

<!DOCTYPE html>
<html>
<head>
  <title>Zodiac Compatibility</title>
  <style>
    * { box-sizing: border-box; margin: 0; padding: 0; }
    body { font-family: system-ui, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; background: #fafafa; }
    h1 { text-align: center; margin-bottom: 8px; }
    .subtitle { text-align: center; color: #666; margin-bottom: 24px; }
    .people { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 24px; }
    .person { background: white; padding: 16px; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
    .person h3 { margin-bottom: 12px; font-size: 16px; }
    label { display: block; font-size: 13px; font-weight: 500; margin-bottom: 4px; color: #444; }
    input, select { width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 6px; font-size: 14px; margin-bottom: 10px; }
    button.check { display: block; width: 100%; padding: 14px; background: #7c3aed; color: white; border: none; border-radius: 12px; font-size: 16px; font-weight: 600; cursor: pointer; margin-bottom: 24px; }
    button.check:hover { background: #6d28d9; }
    button.check:disabled { background: #ccc; cursor: not-allowed; }
    .result { display: none; }
    .score-ring { text-align: center; margin-bottom: 20px; }
    .score-ring .number { font-size: 64px; font-weight: 700; color: #7c3aed; }
    .score-ring .label { font-size: 14px; color: #666; }
    .categories { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 20px; }
    .cat { background: white; padding: 12px; border-radius: 8px; box-shadow: 0 1px 2px rgba(0,0,0,0.05); }
    .cat .name { font-size: 12px; font-weight: 600; text-transform: uppercase; color: #666; }
    .cat .val { font-size: 20px; font-weight: 600; color: #333; }
    .insights { background: white; padding: 16px; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
    .insights h3 { margin-bottom: 8px; font-size: 15px; }
    .insights ul { padding-left: 20px; margin-bottom: 12px; }
    .insights li { font-size: 14px; line-height: 1.6; color: #444; }
    .summary { font-size: 15px; line-height: 1.6; padding: 12px; background: #f5f0ff; border-radius: 8px; margin-bottom: 16px; }
    .loading { text-align: center; padding: 40px; color: #666; }
    @media (max-width: 500px) { .people, .categories { grid-template-columns: 1fr; } }
  </style>
</head>
<body>
  <h1>Zodiac Compatibility</h1>
  <p class="subtitle">Enter two birth charts to see how they match</p>

  <div class="people">
    <div class="person">
      <h3>Person 1</h3>
      <label>Birth date</label>
      <input type="date" id="p1-date" value="1990-07-15" />
      <label>Birth time</label>
      <input type="time" id="p1-time" value="14:30" />
      <label>City</label>
      <select id="p1-city">
        <option value="40.7128,-74.006,-4">New York</option>
        <option value="34.0522,-118.2437,-7">Los Angeles</option>
        <option value="51.5074,-0.1278,0">London</option>
        <option value="19.076,72.8777,5.5">Mumbai</option>
        <option value="35.6762,139.6503,9">Tokyo</option>
        <option value="-33.8688,151.2093,10">Sydney</option>
      </select>
    </div>
    <div class="person">
      <h3>Person 2</h3>
      <label>Birth date</label>
      <input type="date" id="p2-date" value="1992-03-22" />
      <label>Birth time</label>
      <input type="time" id="p2-time" value="09:00" />
      <label>City</label>
      <select id="p2-city">
        <option value="34.0522,-118.2437,-7">Los Angeles</option>
        <option value="40.7128,-74.006,-4">New York</option>
        <option value="51.5074,-0.1278,0">London</option>
        <option value="19.076,72.8777,5.5">Mumbai</option>
        <option value="35.6762,139.6503,9">Tokyo</option>
        <option value="-33.8688,151.2093,10">Sydney</option>
      </select>
    </div>
  </div>

  <button class="check" onclick="checkCompatibility()">Check Compatibility</button>
  <div id="result" class="result"></div>

  <script>
    const API_KEY = 'YOUR_API_KEY'; // Replace with your key from roxyapi.com/pricing

    function parsePerson(prefix) {
      const date = document.getElementById(prefix + '-date').value;
      const time = document.getElementById(prefix + '-time').value + ':00';
      const [lat, lng, tz] = document.getElementById(prefix + '-city').value.split(',');
      return {
        date: date,
        time: time,
        latitude: parseFloat(lat),
        longitude: parseFloat(lng),
        timezone: parseFloat(tz)
      };
    }

    async function checkCompatibility() {
      const btn = document.querySelector('.check');
      btn.disabled = true;
      btn.textContent = 'Calculating...';

      const el = document.getElementById('result');
      el.style.display = 'block';
      el.innerHTML = '<div class="loading">Comparing birth charts...</div>';

      const response = await fetch('https://roxyapi.com/api/v2/astrology/compatibility-score', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-API-Key': API_KEY
        },
        body: JSON.stringify({
          person1: parsePerson('p1'),
          person2: parsePerson('p2')
        })
      });
      const data = await response.json();

      btn.disabled = false;
      btn.textContent = 'Check Compatibility';

      const cats = data.categories || {};
      el.innerHTML = `
        <div class="score-ring">
          <div class="number">${data.overallScore}</div>
          <div class="label">out of 100</div>
        </div>
        ${data.summary ? '<div class="summary">' + data.summary + '</div>' : ''}
        <div class="categories">
          ${Object.entries(cats).map(([k, v]) =>
            '<div class="cat"><div class="name">' + k + '</div><div class="val">' + v + '</div></div>'
          ).join('')}
        </div>
        <div class="insights">
          ${data.strengths && data.strengths.length ? '<h3>Strengths</h3><ul>' + data.strengths.map(s => '<li>' + s + '</li>').join('') + '</ul>' : ''}
          ${data.challenges && data.challenges.length ? '<h3>Challenges</h3><ul>' + data.challenges.map(c => '<li>' + c + '</li>').join('') + '</ul>' : ''}
        </div>
      `;
    }
  </script>
</body>
</html>

Replace YOUR_API_KEY with your key, double-click the file, pick birth data for two people, and click "Check Compatibility."

How it works

Two things happen when you click the button:

1. Build the request body. The parsePerson() function reads the form inputs and creates the object the API expects. The compatibility endpoint needs date, time, latitude, longitude, and timezone for each person. The city dropdown maps city names to coordinates — in a real app you would use a geocoding API or let users type their city.

2. Call the API. A POST request to /api/v2/astrology/compatibility-score sends both people's birth data. The response includes:

  • overallScore — the headline score (0-100)
  • categories — individual scores for romantic, emotional, intellectual, physical, spiritual
  • strengths — what works well between these two charts
  • challenges — potential friction points
  • summary — a one-liner describing the relationship

Make it yours

  • Add a geocoding input — replace the city dropdown with a text input that geocodes via Google Places or OpenStreetMap Nominatim. This lets users enter any city in the world.
  • Show individual charts — call /api/v2/astrology/natal-chart for each person and display their Sun, Moon, and Rising signs alongside the compatibility score.
  • Add synastry details — call /api/v2/astrology/synastry for a deeper analysis showing how specific planets in one chart interact with the other.
  • Vedic compatibility — swap the endpoint to /api/v2/vedic-astrology/compatibility for Gun Milan scoring (out of 36 instead of 100). Popular for Indian matchmaking apps.

Next steps