Example code for looking up MAC address manufacturers using the OUI Master Database API.
The API consists of 256 JSON files organized by the first byte (first 2 hex characters) of the OUI:
https://dagnazty.github.io/OUI-Master-Database/api/
├── index.json # Metadata and available prefixes
├── 00.json # All OUIs starting with 00:XX:XX
├── 01.json # All OUIs starting with 01:XX:XX
├── ...
├── 3C.json # All OUIs starting with 3C:XX:XX (e.g., 3C:D9:2B = HP)
├── ...
└── FF.json # All OUIs starting with FF:XX:XX
Each file contains a JSON object mapping OUI to manufacturer data:
{
"3C:D9:2B": {
"m": "Hewlett Packard",
"s": "HP",
"t": "Computer",
"c": "US"
}
}
Field abbreviations (to minimize payload size):
m = manufacturer (full name)s = short_name (abbreviated)t = device_type (Router, Phone, IoT, etc.)c = country (2-letter code)#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
// Base URL for the OUI API
const char* API_BASE = "https://dagnazty.github.io/OUI-Master-Database/api/";
struct OUIResult {
bool found;
String manufacturer;
String shortName;
String deviceType;
String country;
};
// Normalize MAC to OUI format (XX:XX:XX)
String macToOUI(String mac) {
// Remove separators and convert to uppercase
String clean = "";
for (int i = 0; i < mac.length(); i++) {
char c = mac.charAt(i);
if (isxdigit(c)) {
clean += toupper(c);
}
}
// Take first 6 characters and format
if (clean.length() >= 6) {
return clean.substring(0, 2) + ":" +
clean.substring(2, 4) + ":" +
clean.substring(4, 6);
}
return "";
}
// Get first byte prefix for API lookup
String getPrefix(String mac) {
String clean = "";
for (int i = 0; i < mac.length(); i++) {
char c = mac.charAt(i);
if (isxdigit(c)) {
clean += toupper(c);
}
}
if (clean.length() >= 2) {
return clean.substring(0, 2);
}
return "";
}
// Lookup OUI in the API
OUIResult lookupOUI(String mac) {
OUIResult result = {false, "", "", "", ""};
String prefix = getPrefix(mac);
String oui = macToOUI(mac);
if (prefix.length() == 0 || oui.length() == 0) {
Serial.println("Invalid MAC address");
return result;
}
String url = String(API_BASE) + prefix + ".json";
HTTPClient http;
http.begin(url);
http.setTimeout(10000);
int httpCode = http.GET();
if (httpCode == 200) {
String payload = http.getString();
// Parse JSON - allocate enough memory for ~300-500 entries
DynamicJsonDocument doc(65536); // 64KB should be enough for most prefix files
DeserializationError error = deserializeJson(doc, payload);
if (!error) {
JsonObject entry = doc[oui];
if (!entry.isNull()) {
result.found = true;
result.manufacturer = entry["m"].as<String>();
result.shortName = entry["s"].as<String>();
result.deviceType = entry["t"].as<String>();
result.country = entry["c"].as<String>();
}
} else {
Serial.print("JSON parse error: ");
Serial.println(error.c_str());
}
} else {
Serial.print("HTTP error: ");
Serial.println(httpCode);
}
http.end();
return result;
}
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nConnected!");
// Test lookups
String testMACs[] = {
"00:00:0C:12:34:56", // Cisco
"3C:D9:2B:AA:BB:CC", // HP
"AC:DE:48:11:22:33", // Apple
"24:18:C6:44:55:66" // Espressif (ESP32)
};
for (int i = 0; i < 4; i++) {
Serial.println("\n---------------------------------");
Serial.print("Looking up: ");
Serial.println(testMACs[i]);
OUIResult result = lookupOUI(testMACs[i]);
if (result.found) {
Serial.print("Manufacturer: ");
Serial.println(result.manufacturer);
if (result.shortName.length() > 0) {
Serial.print("Short Name: ");
Serial.println(result.shortName);
}
if (result.deviceType.length() > 0) {
Serial.print("Device Type: ");
Serial.println(result.deviceType);
}
if (result.country.length() > 0) {
Serial.print("Country: ");
Serial.println(result.country);
}
} else {
Serial.println("Not found in database");
}
}
}
void loop() {
// Your main code here
delay(1000);
}
ArduinoJson library (install via Library Manager)#!/usr/bin/env python3
"""
OUI Lookup for Raspberry Pi
Uses the OUI Master Database static API
"""
import requests
import json
import re
from functools import lru_cache
API_BASE = "https://dagnazty.github.io/OUI-Master-Database/api/"
# Cache API responses to avoid repeated requests
@lru_cache(maxsize=256)
def fetch_prefix_data(prefix: str) -> dict:
"""Fetch and cache OUI data for a given prefix."""
url = f"{API_BASE}{prefix}.json"
try:
response = requests.get(url, timeout=10)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error fetching {url}: {e}")
return {}
def normalize_mac(mac: str) -> tuple:
"""
Normalize MAC address to OUI format.
Returns (prefix, oui) tuple.
Accepts formats:
- 00:00:0C:12:34:56
- 00-00-0C-12-34-56
- 00000C123456
- 00:00:0C (just OUI)
"""
# Remove all non-hex characters
clean = re.sub(r'[^0-9A-Fa-f]', '', mac).upper()
if len(clean) < 6:
return None, None
# Get prefix (first 2 chars) and OUI (first 3 bytes formatted)
prefix = clean[:2]
oui = f"{clean[0:2]}:{clean[2:4]}:{clean[4:6]}"
return prefix, oui
def lookup_oui(mac: str) -> dict:
"""
Look up manufacturer information for a MAC address.
Returns dict with:
- found: bool
- manufacturer: str
- short_name: str
- device_type: str
- country: str
"""
result = {
'found': False,
'manufacturer': None,
'short_name': None,
'device_type': None,
'country': None,
'oui': None
}
prefix, oui = normalize_mac(mac)
if not prefix or not oui:
return result
result['oui'] = oui
# Fetch the prefix file
data = fetch_prefix_data(prefix)
if oui in data:
entry = data[oui]
result['found'] = True
result['manufacturer'] = entry.get('m')
result['short_name'] = entry.get('s')
result['device_type'] = entry.get('t')
result['country'] = entry.get('c')
return result
def batch_lookup(macs: list) -> list:
"""Look up multiple MAC addresses efficiently."""
return [lookup_oui(mac) for mac in macs]
# Example usage
if __name__ == "__main__":
test_macs = [
"00:00:0C:12:34:56", # Cisco
"3C:D9:2B:AA:BB:CC", # HP
"AC:DE:48:11:22:33", # Apple
"24:18:C6:44:55:66", # Espressif (ESP32)
"B8:27:EB:AA:BB:CC", # Raspberry Pi
"DC:A6:32:11:22:33", # Raspberry Pi
"E4:5F:01:AA:BB:CC", # Raspberry Pi
]
print("OUI Master Database Lookup")
print("=" * 50)
for mac in test_macs:
result = lookup_oui(mac)
print(f"\nMAC: {mac}")
print(f"OUI: {result['oui']}")
if result['found']:
print(f" Manufacturer: {result['manufacturer']}")
if result['short_name']:
print(f" Short Name: {result['short_name']}")
if result['device_type']:
print(f" Device Type: {result['device_type']}")
if result['country']:
print(f" Country: {result['country']}")
else:
print(" Not found in database")
print("\n" + "=" * 50)
print("Cache info:", fetch_prefix_data.cache_info())
pip install requests
@lru_cache to cache API responses (max 256 prefixes = full database)For devices with storage but limited/no internet:
#!/bin/bash
# Download all API files for offline use
mkdir -p oui_api
cd oui_api
# Download index
curl -sO https://ringmast4r.github.io/OUI-Master-Database/api/index.json
# Download all prefix files (00-FF)
for i in $(seq 0 255); do
prefix=$(printf "%02X" $i)
echo "Downloading $prefix.json..."
curl -sf "https://ringmast4r.github.io/OUI-Master-Database/api/$prefix.json" -o "$prefix.json" 2>/dev/null || true
done
echo "Done! Files saved to oui_api/"
import json
import os
OUI_DIR = "./oui_api"
def lookup_offline(mac: str) -> dict:
"""Offline lookup using downloaded files."""
clean = ''.join(c for c in mac.upper() if c in '0123456789ABCDEF')
if len(clean) < 6:
return {'found': False}
prefix = clean[:2]
oui = f"{clean[0:2]}:{clean[2:4]}:{clean[4:6]}"
filepath = os.path.join(OUI_DIR, f"{prefix}.json")
if not os.path.exists(filepath):
return {'found': False}
with open(filepath) as f:
data = json.load(f)
if oui in data:
entry = data[oui]
return {
'found': True,
'manufacturer': entry.get('m'),
'device_type': entry.get('t'),
'country': entry.get('c')
}
return {'found': False}
| Endpoint | Description | Size |
|---|---|---|
/api/index.json |
Metadata, available prefixes | ~5 KB |
/api/00.json |
OUIs starting with 00:XX:XX | ~50 KB |
/api/3C.json |
OUIs starting with 3C:XX:XX | ~40 KB |
| … | … | ~30-80 KB each |
The API data is compiled from IEEE (public domain), Wireshark (GPLv2), and Nmap (Modified GPLv2). See the main repository LICENSE for details.