# How GenLayer Smart Contracts Access the Internet: The `gl.nondet.web` API Explained

> Discover how GenLayer smart contracts access the internet using the gl.nondet.web API. Learn about fetching live web content and its validation for on-chain use.

- Repository: [GenLayer Labs/genlayer-project-boilerplate](https://github.com/genlayerlabs/genlayer-project-boilerplate)
- Tags: deep-dive
- Published: 2026-08-20

---

**GenLayer contracts access the internet through the `gl.nondet.web` API, a non-deterministic primitive that fetches live web content (HTML, text, screenshots) and requires equivalence-principle validation before results can be used on-chain.**

GenLayer enables **intelligent contracts** to retrieve real-world data directly from the web—a capability that distinguishes its architecture from traditional blockchain platforms. This functionality is implemented in the `genlayerlabs/genlayer-project-boilerplate` repository and centers on a family of nondeterministic web-access methods that must be paired with consensus mechanisms.

## Understanding Non-Deterministic Web Access

Traditional smart contracts are **deterministic**: given the same inputs, all validators must produce identical outputs. Web access breaks this assumption because network latency, content changes, or server responses may vary across validator nodes.

GenLayer solves this through **two-stage execution**:

1. **Fetch** external data using `gl.nondet.web` methods
2. **Validate** results using equivalence-principle functions like `gl.eq_principle.strict_eq`

This pattern ensures validators reach consensus on the same interpretation of web content before state changes are finalized.

## The `gl.nondet.web` API Methods

The `gl.nondet.web` module provides four primary methods for internet access:

- **`gl.nondet.web.get(url, headers={})`** — Performs an HTTP GET request and returns a `Response` object
- **`gl.nondet.web.post(url, body, headers={})`** — Performs an HTTP POST request with a request body
- **`gl.nondet.web.render(url, mode="text")`** — Retrieves rendered page content as plain text
- **`gl.nondet.web.render(url, mode="html")`** — Retrieves raw HTML source
- **`gl.nondet.web.render(url, mode="screenshot")`** — Captures a screenshot image of the page

All methods return data that must be processed through an equivalence principle before on-chain use.

## Complete Web Access Pattern: Fetch, Prompt, Validate

The [`contracts/football_bets.py`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/contracts/football_bets.py) file demonstrates the full implementation pattern for how GenLayer contracts access the internet. This contract resolves football bets by scraping live match results from BBC Sport.

### Step 1: Compose the Target URL

```python
match_resolution_url = (
    "https://www.bbc.com/sport/football/scores-fixtures/" + game_date
)  # → line 62

```

### Step 2: Fetch Page Content with `gl.nondet.web.render`

```python
web_data = gl.nondet.web.render(resolution_url, mode="text")  # → line 31

```

The `mode="text"` parameter returns a clean, parseable text representation of the page rather than raw HTML.

### Step 3: Extract Structured Data via LLM

```python
task = f"""
Extract the match result for:
Team 1: {team1}
Team 2: {team2}

Web content:
{web_data}

Respond in JSON:
{{
    "score": str,
    "winner": int
}}
"""
result = gl.nondet.exec_prompt(task, response_format="json")  # → line 51

```

### Step 4: Validate with Equivalence Principle

```python
result_json = json.loads(gl.eq_principle.strict_eq(get_match_result))  # → line 54

```

The `strict_eq` wrapper ensures all validators agree on the identical JSON string before the result is accepted.

## Full Working Example: `FootballBets` Contract

```python
def _check_match(self, resolution_url: str, team1: str, team2: str) -> dict:
    # 1️⃣ Pull the page content

    web_data = gl.nondet.web.render(resolution_url, mode="text")   # line 31

    # 2️⃣ Build a prompt that asks the LLM to parse the score/winner

    task = f"""
    Extract the match result for:
    Team 1: {team1}
    Team 2: {team2}

    Web content:
    {web_data}

    Respond in JSON:
    {{
        "score": str,
        "winner": int
    }}
    """
    # 3️⃣ Ask the LLM and enforce a JSON response

    result = gl.nondet.exec_prompt(task, response_format="json")   # line 51

    # 4️⃣ Verify the nondeterministic output

    result_json = json.loads(gl.eq_principle.strict_eq(lambda: json.dumps(result, sort_keys=True)))  # line 54

    return result_json

```

## Alternative Patterns for Internet Access

### Direct GET Request for API Data

```python
@gl.public.view
def fetch_price(self, ticker: str) -> str:
    url = f"https://api.example.com/price?ticker={ticker}"
    resp = gl.nondet.web.get(url)                     # ← HTTP GET

    # Validate response content

    price = gl.eq_principle.strict_eq(lambda: resp.body)
    return price

```

### Screenshot Verification

```python
@gl.public.view
def get_page_snapshot(self, url: str) -> bytes:
    img = gl.nondet.web.render(url, mode="screenshot")
    # Validators confirm the image hash matches

    img_hash = gl.eq_principle.strict_eq(lambda: hashlib.sha256(img).hexdigest())
    return img

```

## Key Source Files in the Repository

| File | Purpose | Key Lines |
|------|---------|-----------|
| [`contracts/football_bets.py`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/contracts/football_bets.py) | Web rendering, LLM prompting, equivalence-principle validation | 31-34 (web fetch), 51-54 (LLM & validation) |
| [`contracts/__init__.py`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/contracts/__init__.py) | Contract module registration | — |
| [`tests/direct/test_views.py`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/tests/direct/test_views.py) | Mock web calls in direct-mode tests | — |
| [`config/genlayer_config.py`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/config/genlayer_config.py) | Network endpoint configuration | — |

## Summary

- **GenLayer smart contracts access the internet through `gl.nondet.web`**, a non-deterministic API that supports GET, POST, and rendered content retrieval
- **All web calls require equivalence-principle validation** (`gl.eq_principle.strict_eq` or similar) to achieve validator consensus
- **Three render modes** are available: `"text"` for clean extraction, `"html"` for raw markup, and `"screenshot"` for visual verification
- **The `FootballBets` contract** in [`contracts/football_bets.py`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/contracts/football_bets.py) demonstrates the complete pattern: URL construction, `gl.nondet.web.render`, LLM processing with `gl.nondet.exec_prompt`, and strict equality validation

## Frequently Asked Questions

### What makes `gl.nondet.web` "non-deterministic"?

The `gl.nondet.web` methods are non-deterministic because web servers may return different responses to different validators—due to timing, caching, geo-location, or dynamic content. Unlike deterministic operations that produce identical outputs on every node, these calls require **equivalence-principle validation** so validators can agree on a single canonical result before updating on-chain state.

### Can GenLayer contracts access any website?

Yes, `gl.nondet.web.get` and `gl.nondet.web.render` can target any public URL. However, the **equivalence principle** may fail for highly dynamic or personalized content. For reliable consensus, contracts should target stable, public sources or use `mode="text"` to reduce noise from JavaScript-rendered variations.

### What happens if validators disagree on web content?

If validators produce different outputs from a `gl.nondet.web` call, the **equivalence-principle function** (e.g., `gl.eq_principle.strict_eq`) detects the mismatch and halts execution. The transaction does not finalize until a sufficient majority agrees on the same result, preserving network consensus.

### How do you test contracts that use internet access?

The [`tests/direct/test_views.py`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/tests/direct/test_views.py) file demonstrates **mocking web calls** in direct-mode tests. Developers can simulate `gl.nondet.web` responses without making actual network requests, enabling deterministic test behavior while preserving the production code structure.