DEV Community

GuGuData
GuGuData

Posted on

Build a University Comparison Tool with QS Rankings and Global University Data APIs

Build a University Comparison Tool with QS Rankings and Global University Data APIs

University search products often need two different types of education data:

  • profile data, such as institution names, countries, regions, and cities
  • ranking context, such as QS World University Rankings positions

Those two datasets answer different questions. Profile data helps a product identify and normalize institutions. Ranking data helps users compare schools with additional context. In this tutorial, we will build a small API-first workflow that combines both.

The examples use:

You can inspect live sample responses before connecting production access:

What we are building

The goal is a simple university comparison flow:

  1. Search university profiles by name.
  2. Normalize the institution record.
  3. Request QS ranking data for the same or related name.
  4. Merge the profile and ranking fields for display.

This pattern works for education search, CRM enrichment, research tools, admissions platforms, and internal reporting dashboards.

Step 1: Search university profiles

Start with profile data when the user enters an institution name. Profile data is the safer first step because it is broader than ranking data.

async function searchUniversityProfiles(name, appkey) {
  const params = new URLSearchParams({
    appkey,
    name,
    pageIndex: "1",
    pageSize: "10",
  });

  const response = await fetch(
    `https://api.gugudata.io/v1/metadata/global-university?${params}`
  );

  if (!response.ok) {
    throw new Error(`Global University API failed: ${response.status}`);
  }

  return response.json();
}
Enter fullscreen mode Exit fullscreen mode

For a production app, keep the API key on the server side. The browser can call your backend, and your backend can call the data API.

Step 2: Pick the best profile candidate

Search results can include multiple institutions with similar names. A basic scoring function can prefer exact name matches and country matches.

function pickBestUniversityProfile(records, expectedCountry) {
  return records
    .map((record) => {
      const countryScore =
        expectedCountry && record.country === expectedCountry ? 10 : 0;
      const nameScore = record.name ? Math.min(record.name.length, 20) : 0;

      return {
        record,
        score: countryScore + nameScore,
      };
    })
    .sort((a, b) => b.score - a.score)[0]?.record;
}
Enter fullscreen mode Exit fullscreen mode

This does not need to be complicated at first. The important part is to separate profile matching from ranking comparison.

Step 3: Request QS ranking context

Once you have a likely institution name, use ranking data to enrich the result.

async function searchQsRankings(name, appkey) {
  const params = new URLSearchParams({
    appkey,
    name,
    pageIndex: "1",
    pageSize: "10",
  });

  const response = await fetch(
    `https://api.gugudata.io/v1/metadata/qs-global-university-ranking?${params}`
  );

  if (!response.ok) {
    throw new Error(`QS Rankings API failed: ${response.status}`);
  }

  return response.json();
}
Enter fullscreen mode Exit fullscreen mode

The ranking API should not replace the profile API. It adds ranking-specific context where that context is available.

Step 4: Merge profile and ranking data

After both requests complete, merge the results into one view model.

async function buildUniversityComparison({ name, country, appkey }) {
  const profileResponse = await searchUniversityProfiles(name, appkey);
  const profiles = profileResponse.data || profileResponse.items || [];
  const profile = pickBestUniversityProfile(profiles, country);

  const qsResponse = await searchQsRankings(profile?.name || name, appkey);
  const rankingRecords = qsResponse.data || qsResponse.items || [];
  const ranking = rankingRecords[0] || null;

  return {
    name: profile?.name || name,
    country: profile?.country || country || null,
    city: profile?.city || null,
    qsRank: ranking?.rank || ranking?.ranking || null,
    rankingSource: ranking ? "QS World University Rankings" : null,
    profile,
    ranking,
  };
}
Enter fullscreen mode Exit fullscreen mode

The exact response fields can vary by endpoint and version, so inspect the live demo and response parameter table before wiring the data into a production UI.

Product tips

For education search, show profile data first and ranking data second. Users usually need to identify the institution before comparing ranking position.

For CRM enrichment, store profile identifiers and normalized location fields. Ranking data can be refreshed separately on a schedule.

For market research, keep profile matching rules visible to analysts. Ranking comparisons are only useful when the underlying institution match is correct.

Where to go next

Use the live docs and demo pages to validate fields before production access:

The cleanest integration path is to test the demo response, confirm the fields, then subscribe to production access for the endpoint you need.

Top comments (0)