Skip to main content

Overview

The Knowledge Tooltip extension integrates with Wikidata to provide structured, factual information about entities (people, places, organizations, concepts). Wikidata serves as a knowledge base with machine-readable data.
Wikidata provides structured facts organized as properties and claims. The extension uses two APIs: the Search API to find entity IDs, and the Entity Data API to retrieve detailed information.

Features Using This API

  • Encyclopedia Tab: Enriches Wikipedia content with structured facts
  • Entity Recognition: Identifies proper nouns and concepts
  • Multi-language Facts: Returns data in the user’s preferred language with fallbacks
  • Structured Information: Birth dates, occupations, countries, populations, and more

Search Entities Endpoint

Searches Wikidata to find the best matching entity and returns its ID.

Endpoint

GET https://www.wikidata.org/w/api.php?action=wbsearchentities&search={term}&language={lang}&limit=1&format=json&origin=*
action
string
default:"wbsearchentities"
Wikidata API action for entity search
Search query (URL-encoded)
language
string
required
Language code for search and labels (en, ar, etc.)
limit
number
default:"1"
Maximum number of results to return
format
string
default:"json"
Response format
origin
string
default:"*"
CORS origin (required for cross-origin requests)

Implementation

From background.js:141-159:
async function searchWikidataEntity(term, language) {
  const langCode = language === 'ar' ? 'ar' : 'en';
  const url = `https://www.wikidata.org/w/api.php?action=wbsearchentities&search=${encodeURIComponent(term)}&language=${langCode}&limit=1&format=json&origin=*`;

  const response = await fetch(url);

  if (!response.ok) {
    throw new Error(`HTTP ${response.status}`);
  }

  const data = await response.json();

  if (data.search && data.search.length > 0) {
    return data.search[0];
  }

  return null;
}

Request Example

chrome.runtime.sendMessage({
  action: 'searchWikidata',
  term: 'Albert Einstein',
  language: 'en'
}, (response) => {
  if (response.success && response.data) {
    const entityId = response.data.id;
    console.log(`Found entity: ${entityId}`);
  }
});

Response Structure

search
array
Array of matching entities (limited to 1 by default)

Response Example

{
  "search": [
    {
      "id": "Q937",
      "label": "Albert Einstein",
      "description": "German-born theoretical physicist (1879-1955)",
      "url": "https://www.wikidata.org/wiki/Q937"
    }
  ]
}

Entity Data Endpoint

Retrieves detailed information about a specific Wikidata entity using its ID.

Endpoint

GET https://www.wikidata.org/wiki/Special:EntityData/{entityId}.json
entityId
string
required
Wikidata entity ID (e.g., Q937, Q42, Q30)

Implementation

From background.js:161-249:
async function fetchWikidataEntity(entityId, language) {
  const url = `https://www.wikidata.org/wiki/Special:EntityData/${entityId}.json`;

  const response = await fetch(url);

  if (!response.ok) {
    throw new Error(`HTTP ${response.status}`);
  }

  const data = await response.json();
  const entity = data.entities[entityId];

  if (!entity) {
    throw new Error('Entity not found');
  }

  const langCode = language === 'ar' ? 'ar' : 'en';
  const fallbackLang = langCode === 'ar' ? 'en' : 'ar';

  // Extract label and description with language fallback
  const label = entity.labels?.[langCode]?.value || 
                entity.labels?.[fallbackLang]?.value || 
                entityId;
  const description = entity.descriptions?.[langCode]?.value || 
                      entity.descriptions?.[fallbackLang]?.value || 
                      '';

  // Extract and process claims/properties
  const claims = entity.claims || {};
  const facts = [];

  // ... (property extraction logic)

  return { label, description, facts };
}

Request Example

chrome.runtime.sendMessage({
  action: 'fetchWikidataEntity',
  entityId: 'Q937',
  language: 'en'
}, (response) => {
  if (response.success) {
    console.log(response.data.label);
    console.log(response.data.description);
    response.data.facts.forEach(fact => {
      console.log(`${fact.label}: ${fact.value}`);
    });
  }
});

Processed Response Structure

The extension processes the raw Wikidata JSON into a simplified format:
label
string
Entity name in the requested language (with fallback)
description
string
Short description in the requested language (with fallback)
facts
array
Array of extracted property-value pairs

Processed Response Example

{
  "label": "Albert Einstein",
  "description": "German-born theoretical physicist",
  "facts": [
    { "label": "Born", "value": "March 14, 1879" },
    { "label": "Died", "value": "April 18, 1955" },
    { "label": "Occupation", "value": "physicist, university teacher" },
    { "label": "Country", "value": "Germany, United States" },
    { "label": "Awards", "value": "Nobel Prize in Physics" }
  ]
}

Supported Properties

The extension extracts and displays specific Wikidata properties mapped to human-readable labels:

Person Properties

Property IDEnglish LabelArabic LabelExample Value
P569Bornتاريخ الميلاد”March 14, 1879”
P570Diedتاريخ الوفاة”April 18, 1955”
P27Countryالجنسية”Germany”
P106Occupationالمهنة”physicist”
P69Educationالتعليم”ETH Zurich”
P26Spouseالزوج/ة”Mileva Marić”
P40Childrenالأبناء”Hans Albert Einstein”
P166Awardsجوائز”Nobel Prize in Physics”
P800Notable workأعمال بارزة”Theory of relativity”

Place Properties

Property IDEnglish LabelArabic LabelExample Value
P17Countryالبلد”United States”
P1082Populationعدد السكان”8,336,817”
P625Coordinatesالإحداثيات”40.7128, -74.0060”
P36Capitalالعاصمة”Washington, D.C.”
P2046Areaالمساحة”9,833,520 km²”
P421Timezoneالمنطقة الزمنية”UTC-5”

Organization Properties

Property IDEnglish LabelArabic LabelExample Value
P571Foundedتاريخ التأسيس”April 1, 1976”
P112Founded byالمؤسس”Steve Jobs, Steve Wozniak”
P159Headquartersالمقر”Cupertino, California”
P169CEOالرئيس التنفيذي”Tim Cook”
P452Industryالقطاع”Technology”
P856Websiteالموقع الرسميhttps://www.apple.com
The extension displays up to 3 values per property and processes up to ~30 different property types. See background.js:189-220 for the complete property mapping.

Data Type Processing

Wikidata values come in different data types that require specific formatting:

Time Values

From background.js:319-337:
case 'time': {
  const time = datavalue.value.time;
  // Parse +YYYY-MM-DDT00:00:00Z format
  const match = time.match(/([+-]\d+)-(\d{2})-(\d{2})/);
  if (match) {
    const year = parseInt(match[1]);
    const month = parseInt(match[2]);
    const day = parseInt(match[3]);
    if (month === 0 && day === 0) return `${Math.abs(year)}`;
    const date = new Date(Math.abs(year), month - 1, day);
    const options = { year: 'numeric', month: 'long', day: 'numeric' };
    try {
      return date.toLocaleDateString(langCode, options);
    } catch {
      return `${day}/${month}/${Math.abs(year)}`;
    }
  }
  return time;
}

Quantity Values

From background.js:338-345:
case 'quantity': {
  const amount = parseFloat(datavalue.value.amount);
  try {
    return amount.toLocaleString(langCode);
  } catch {
    return amount.toString();
  }
}

Coordinate Values

From background.js:350-354:
case 'globecoordinate': {
  const lat = datavalue.value.latitude.toFixed(4);
  const lon = datavalue.value.longitude.toFixed(4);
  return `${lat}, ${lon}`;
}

Other Data Types

  • Entity references (wikibase-entityid): Returns the entity ID (e.g., Q42)
  • Monolingual text (monolingualtext): Extracts the text value
  • Strings (string): Returns as-is

Language Fallback Strategy

Not all entities have labels, descriptions, or property values in all languages. The extension implements a fallback mechanism.
From background.js:178-184:
const langCode = language === 'ar' ? 'ar' : 'en';
const fallbackLang = langCode === 'ar' ? 'en' : 'ar';

const label = entity.labels?.[langCode]?.value || 
              entity.labels?.[fallbackLang]?.value || 
              entityId;
const description = entity.descriptions?.[langCode]?.value || 
                    entity.descriptions?.[fallbackLang]?.value || 
                    '';
Fallback order:
  1. Requested language (e.g., Arabic)
  2. Opposite language (e.g., English)
  3. Entity ID as last resort

Error Handling

From background.js:50-62:
if (message.action === 'searchWikidata') {
  searchWikidataEntity(message.term, message.language)
    .then(data => sendResponse({ success: true, data }))
    .catch(error => sendResponse({ success: false, error: toErrMsg(error) }));
  return true;
}

if (message.action === 'fetchWikidataEntity') {
  fetchWikidataEntity(message.entityId, message.language)
    .then(data => sendResponse({ success: true, data }))
    .catch(error => sendResponse({ success: false, error: toErrMsg(error) }));
  return true;
}

Common Error Scenarios

ErrorCauseHandling
HTTP 404Entity ID doesn’t existReturn null, don’t display Wikidata section
Entity not foundResponse missing entity dataThrow error, caught by message handler
No search resultsSearch returns empty arrayReturn null from search function
HTTP 500Wikidata server errorDisplay error state in UI

Usage Flow

Typical workflow for fetching entity information:
// Step 1: Search for entity ID
chrome.runtime.sendMessage({
  action: 'searchWikidata',
  term: 'Paris',
  language: 'en'
}, (searchResponse) => {
  if (searchResponse.success && searchResponse.data) {
    const entityId = searchResponse.data.id;
    
    // Step 2: Fetch detailed entity data
    chrome.runtime.sendMessage({
      action: 'fetchWikidataEntity',
      entityId: entityId,
      language: 'en'
    }, (entityResponse) => {
      if (entityResponse.success) {
        displayWikidataFacts(entityResponse.data);
      }
    });
  }
});

Rate Limits

Wikidata API rate limits:
  • 200 requests/second for anonymous users
  • No authentication required
  • Consider caching entity data locally

Best Practices

  1. Cache entity data: Store fetched entities by ID to avoid repeated requests
  2. Batch entity lookups: If needing multiple entities, consider using the wbgetentities action
  3. Minimize search calls: Use search results carefully; they’re more expensive than entity fetches

Raw Entity Data Structure

The raw Wikidata entity JSON is complex. Key sections:
{
  "entities": {
    "Q937": {
      "id": "Q937",
      "labels": {
        "en": { "language": "en", "value": "Albert Einstein" },
        "ar": { "language": "ar", "value": "ألبرت أينشتاين" }
      },
      "descriptions": {
        "en": { "language": "en", "value": "German-born theoretical physicist" }
      },
      "claims": {
        "P569": [
          {
            "mainsnak": {
              "datavalue": {
                "type": "time",
                "value": {
                  "time": "+1879-03-14T00:00:00Z",
                  "timezone": 0,
                  "precision": 11
                }
              }
            }
          }
        ],
        "P106": [
          {
            "mainsnak": {
              "datavalue": {
                "type": "wikibase-entityid",
                "value": { "id": "Q169470" }
              }
            }
          }
        ]
      }
    }
  }
}

Build docs developers (and LLMs) love