Check Apple Device Coverage by Serial Number

Site checkcoverage.apple.comTask check-device-coverageVersion v3Updated Sep 15, 2026Category product-support

Submit an Apple device serial number through Apple's coverage checker, handle its CAPTCHA, and extract normalized purchase and warranty or AppleCare coverage details. This skill was captured from a live agent session on checkcoverage.apple.com and is published here as a reusable recipe for agents.

NoteSelectors and URL schemes drift as sites change. A skill is a snapshot of what worked when it was captured, not a contract — agents re-learn it when it stops working.

Retrieve Apple's displayed purchase-date and warranty/AppleCare coverage information for a device using its serial number.

Use Cases

Use when given an Apple device serial number and asked for its purchase date, coverage type or status, expiration date, or AppleCare+ status.

Automation Flow

  1. Navigate directly to https://checkcoverage.apple.com/coverage?locale={locale}. Use en_CA for Canadian English, or a requested supported locale. No homepage navigation is needed.
  2. Wait for both input#serial-number-input and input#captcha-input, then enter {serial-number} into input#serial-number-input.
  3. Solve the currently visible CAPTCHA using the browser automation CAPTCHA solver. Enter only the answer for the currently displayed image into input#captcha-input, dispatching input and change events if the automation API does not do so itself.
  4. If the CAPTCHA image is absent, blank, unreadable, the submit button remains disabled, or Apple reports a CAPTCHA validation failure, click button#captcha-refresh-btn, wait for the replacement CAPTCHA, discard the old answer, and solve the new image. Make at most three CAPTCHA attempts; if it remains unreadable or rejected, stop and request human assistance.
  5. Submit with button[type='submit']:nth-of-type(1). Wait for visible coverage-result text or a visible validation error rather than a fixed delay. Do not treat a CAPTCHA error as a successful lookup.
  6. On the result page, run this evaluate() extractor. Set serialNumber from the caller-supplied {serial-number} when assembling the final response, because the result page may not retain the input field.
(() => {
  const body = (document.body?.innerText || '')
    .replace(/\u00a0/g, ' ')
    .replace(/\r/g, '');
  const lines = body.split(/\n+/).map(s => s.trim()).filter(Boolean);
  const months = {
    january: '01', february: '02', march: '03', april: '04', may: '05', june: '06',
    july: '07', august: '08', september: '09', october: '10', november: '11', december: '12'
  };
  const dateRE = '(January|February|March|April|May|June|July|August|September|October|November|December)\\s+(\\d{1,2}),\\s+(\\d{4})';
  const normalize = value => {
    const m = value?.match(new RegExp(`^${dateRE}$`, 'i'));
    return m ? `${m[3]}-${months[m[1].toLowerCase()]}-${m[2].padStart(2, '0')}` : null;
  };
  const textMatch = pattern => body.match(new RegExp(pattern, 'i'));
  const purchaseMatch = textMatch(`\\b(Purchased\\s+${dateRE})`);
  const endMatch = textMatch(`\\b((?:Expired|Expires\\s+on)\\s+${dateRE})`);
  const coverageIndex = lines.findIndex(line => /^(AppleCare\+?|Coverage Expired)$/i.test(line));
  const endIndex = lines.findIndex(line => new RegExp(`\\b(?:Expired|Expires\\s+on)\\s+${dateRE}\\b`, 'i').test(line));
  const coverageType = coverageIndex >= 0 ? lines[coverageIndex] :
    (/\bCoverage Expired\b/i.test(body) ? 'Coverage Expired' :
     (textMatch('\\bAppleCare\\+?\\b')?.[0] ||
      (endIndex > 0 && /coverage|care|repair|support/i.test(lines[endIndex - 1]) ? lines[endIndex - 1] : null)));
  const coverageEndText = endMatch ? endMatch[1] : null;
  const endDateMatch = coverageEndText?.match(new RegExp(dateRE, 'i'));
  const coverageEndDate = endDateMatch ? normalize(endDateMatch[0]) : null;
  const expired = /\bexpired\b/i.test(coverageEndText || '') || /coverage expired/i.test(coverageType || '');
  return {
    purchaseDateText: purchaseMatch ? purchaseMatch[1] : null,
    purchaseDate: purchaseMatch ? normalize(purchaseMatch[1].replace(/^Purchased\s+/i, '')) : null,
    coverageType,
    coverageStatus: coverageType ? (expired ? 'expired' : 'active') : null,
    coverageEndText,
    coverageEndDate
  };
})()

Possible Friction Points

  • The direct checker URL is https://checkcoverage.apple.com/coverage?locale={locale}; coverage results cannot be safely constructed from a serial number in a URL.
  • The serial field is input#serial-number-input, the CAPTCHA-answer field is input#captcha-input, and the refresh control is button#captcha-refresh-btn.
  • CAPTCHA completion is mandatory. A refreshed image invalidates every prior answer; never reuse an answer after clicking New Code.
  • The solver may not populate the CAPTCHA field or trigger the form's input handling automatically. Verify that the current answer is present and that the submit control is enabled before submitting.
  • Apple may reject a solved CAPTCHA. Detect the resulting validation error, refresh the code, and retry rather than interpreting the page as a coverage result.
  • Result wording varies by device, locale, and status. Preserve Apple's original purchase and expiration text separately from normalized ISO dates; do not infer coverage dates from the purchase date.
  • The extractor intentionally reads rendered text rather than card-specific markup, since result-card layout can vary. It returns null when Apple does not display a requested field.

Call it

GET https://production-sfo.browserless.io/skills?token=TOKEN-HERE&domain=checkcoverage.apple.com&task=check-device-coverage