Skip to content
Back to skills

Doi Resolution Guide

ASecurity

DOI content negotiation and metadata retrieval techniques

  • 3,639 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added June 6, 2026
researchpythongobashgitapi

Works with

  • api

Security analysis

A100/100

Scanned June 6, 2026

npx -y skills add brycewang-stanford/Auto-Empirical-Research-Skills --skill doi-resolution-guide --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Doi Resolution Guide?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Doi Resolution Guide
[![Security: A β€” Skills Directory](https://www.skillsdirectory.com/api/skills/brycewang-stanford-doi-resolution-guide/badge)](https://www.skillsdirectory.com/skills/brycewang-stanford-doi-resolution-guide)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: doi-resolution-guide
description: "DOI content negotiation and metadata retrieval techniques"
metadata:
  openclaw:
    emoji: "πŸ”—"
    category: "literature"
    subcategory: "metadata"
    keywords: ["DOI resolution", "digital object identifier", "citation statistics"]
    source: "wentor-research-plugins"
---

# DOI Resolution Guide

Master DOI content negotiation to programmatically retrieve structured metadata, citation data, and formatted references from any Digital Object Identifier.

## What Is DOI Content Negotiation?

Every DOI (e.g., `10.1038/s41586-021-03819-2`) resolves to a landing page by default. However, the DOI system supports HTTP content negotiation: by sending different `Accept` headers, you can retrieve structured metadata in various formats instead of an HTML page.

The DOI resolver endpoint is `https://doi.org/{doi}` or equivalently `https://dx.doi.org/{doi}`.

## Supported Metadata Formats

| Accept Header | Format | Use Case |
|---------------|--------|----------|
| `application/vnd.citationstyles.csl+json` | CSL-JSON | Programmatic metadata extraction |
| `text/x-bibliography; style=apa` | Formatted citation | Ready-to-paste APA reference |
| `text/x-bibliography; style=bibtex` | BibTeX | LaTeX bibliography import |
| `application/x-bibtex` | BibTeX (alt) | LaTeX bibliography import |
| `application/rdf+xml` | RDF/XML | Linked data applications |
| `text/turtle` | Turtle RDF | Linked data applications |
| `application/vnd.crossref.unixref+xml` | CrossRef Unixref | Full CrossRef metadata |

## Retrieving Metadata via Content Negotiation

### Get CSL-JSON (Most Useful for Programmatic Access)

```bash
curl -LH "Accept: application/vnd.citationstyles.csl+json" \
  https://doi.org/10.1038/s41586-021-03819-2
```

```python
import requests

doi = "10.1038/s41586-021-03819-2"
headers = {"Accept": "application/vnd.citationstyles.csl+json"}
response = requests.get(f"https://doi.org/{doi}", headers=headers, allow_redirects=True)

metadata = response.json()
print(f"Title: {metadata['title']}")
print(f"Authors: {', '.join(a.get('family', '') for a in metadata.get('author', []))}")
print(f"Journal: {metadata.get('container-title', 'N/A')}")
print(f"Year: {metadata.get('published', {}).get('date-parts', [[None]])[0][0]}")
print(f"Type: {metadata.get('type')}")
```

### Get a Formatted Citation

```bash
# APA format
curl -LH "Accept: text/x-bibliography; style=apa" \
  https://doi.org/10.1038/s41586-021-03819-2

# Chicago format
curl -LH "Accept: text/x-bibliography; style=chicago-author-date" \
  https://doi.org/10.1038/s41586-021-03819-2

# Harvard format
curl -LH "Accept: text/x-bibliography; style=harvard-cite-them-right" \
  https://doi.org/10.1038/s41586-021-03819-2
```

### Get BibTeX for LaTeX

```bash
curl -LH "Accept: application/x-bibtex" \
  https://doi.org/10.1038/s41586-021-03819-2
```

Output:

```bibtex
@article{Jumper_2021,
  title={Highly accurate protein structure prediction with AlphaFold},
  volume={596},
  DOI={10.1038/s41586-021-03819-2},
  journal={Nature},
  author={Jumper, John and Evans, Richard and ...},
  year={2021},
  pages={583--589}
}
```

## Using the CrossRef API

The CrossRef API provides richer metadata and supports batch queries without content negotiation.

### Single Paper Lookup

```python
import requests

doi = "10.1038/s41586-021-03819-2"
response = requests.get(
    f"https://api.crossref.org/works/{doi}",
    headers={"User-Agent": "ResearchClaw/1.0 (mailto:you@university.edu)"}
)

work = response.json()["message"]
print(f"Title: {work['title'][0]}")
print(f"Publisher: {work['publisher']}")
print(f"Citation count: {work.get('is-referenced-by-count', 0)}")
print(f"Reference count: {work.get('references-count', 0)}")
print(f"License: {work.get('license', [{}])[0].get('URL', 'N/A')}")
```

### Batch DOI Resolution

```python
dois = [
    "10.1038/s41586-021-03819-2",
    "10.1126/science.abj8754",
    "10.1016/j.cell.2021.06.025"
]

results = []
for doi in dois:
    resp = requests.get(
        f"https://api.crossref.org/works/{doi}",
        headers={"User-Agent": "ResearchClaw/1.0 (mailto:you@university.edu)"}
    )
    if resp.status_code == 200:
        results.append(resp.json()["message"])
    else:
        print(f"Failed to resolve: {doi}")
```

## DOI Validation and Normalization

```python
import re

def normalize_doi(raw_input):
    """Extract and normalize a DOI from various input formats."""
    # Match DOI pattern: 10.XXXX/...
    match = re.search(r'(10\.\d{4,9}/[^\s]+)', raw_input)
    if match:
        doi = match.group(1)
        # Remove trailing punctuation
        doi = doi.rstrip('.,;:)')
        return doi.lower()
    return None

# Examples
normalize_doi("https://doi.org/10.1038/s41586-021-03819-2")  # 10.1038/s41586-021-03819-2
normalize_doi("DOI: 10.1038/s41586-021-03819-2.")            # 10.1038/s41586-021-03819-2
normalize_doi("See paper at doi.org/10.1038/s41586-021-03819-2 for details")  # works too
```

## Practical Tips

- **Polite pool**: CrossRef provides faster responses to requests with a `User-Agent` header that includes a `mailto:` contact. This is their "polite pool" with higher rate limits.
- **OpenAlex alternative**: OpenAlex (https://api.openalex.org/works/doi:10.xxx/yyy) provides similar metadata for free, with richer entity linking.
- **Handle redirects**: Always use `allow_redirects=True` (or `-L` in curl) as DOIs redirect through the resolver.
- **Caching**: DOI metadata rarely changes. Cache resolved metadata locally to avoid redundant API calls.
- **Rate limits**: CrossRef allows 50 requests/second in the polite pool. For bulk operations, use their data dumps instead.

## See Also

- [doi-content-negotiation](../doi-content-negotiation/SKILL.md) -- Detailed API reference for retrieving metadata in multiple formats via HTTP content negotiation.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…