How to Implement Web Requests with gl.nondet.web.render in GenLayer Smart Contracts

You can implement web requests in GenLayer smart contracts by calling gl.nondet.web.render to fetch external page content, then processing that content through an LLM prompt wrapped in an equivalence-principle verification to maintain deterministic consensus.

The genlayer-project-boilerplate repository demonstrates this exact pattern in production contract code. Learning how to implement web requests with gl.nondet.web.render in GenLayer allows your smart contracts to ingest real-world data while preserving the blockchain's deterministic guarantees.

How to Implement Web Requests with gl.nondet.web.render

GenLayer contracts call external web resources through the non-deterministic API gl.nondet.web. The architectural flow follows five concrete steps to keep the contract deterministic while still allowing dynamic web data:

  1. Call gl.nondet.web.render to fetch raw page content.
  2. Compose an LLM prompt that instructs the model to output only JSON.
  3. Execute the prompt with gl.nondet.exec_prompt(..., response_format="json").
  4. Validate the LLM output using an equivalence-principle function such as gl.eq_principle.strict_eq.
  5. Parse the verified JSON and use the data inside the contract logic.

Fetch Page Content Using gl.nondet.web.render

The render method retrieves a page's content in either text or HTML form. In contracts/football_bets.py, the private _check_match helper uses mode="text" to strip markup and obtain plain text suitable for LLM consumption.

from genlayer import *

def fetch_match_text(url: str) -> str:
    # Retrieve the page as plain text (no HTML tags)

    return gl.nondet.web.render(url, mode="text")

Compose an LLM Prompt for Structured Extraction

After fetching raw page content, build an LLM prompt that instructs the model to output only JSON. The prompt should embed the web data alongside explicit schema requirements.

def extract_match_info(url: str, team1: str, team2: str) -> dict:
    # 1️⃣ Get raw page content

    page = fetch_match_text(url)

    # 2️⃣ Build an LLM prompt that forces JSON output

    prompt = f"""
    Extract the match result for:
    Team 1: {team1}
    Team 2: {team2}
    
    Web content:
    {page}
    
    Respond in JSON:
    {{
        "score": str,   // e.g. "1:2" or "-" if unresolved
        "winner": int   // 0 for draw, -1 if unresolved
    }}
    It is mandatory that you respond only using the JSON format above,
    nothing else.
    """

    # 3️⃣ Execute the prompt (JSON response format)

    llm_result = gl.nondet.exec_prompt(prompt, response_format="json")

    # 4️⃣ Verify output with strict equivalence principle

    verified = json.loads(gl.eq_principle.strict_eq(lambda: json.dumps(llm_result, sort_keys=True)))

    return verified

Validate Output with the Equivalence Principle

Because web fetches and LLM calls are non-deterministic, GenLayer requires an equivalence-principle function to ensure validators agree on the result. The boilerplate uses gl.eq_principle.strict_eq to verify that repeated executions produce identical JSON output before the contract accepts the data.

Parse Verified Data Inside the Contract

Once sanitized, parse the JSON and use the fields directly in your contract logic. The FootballBets contract demonstrates this inside its _check_match method, located in contracts/football_bets.py (lines 30-33).

class FootballBets(gl.Contract):
    # ...

    def _check_match(self, resolution_url: str, team1: str, team2: str) -> dict:
        # The core web-render + LLM extraction logic

        def get_match_result() -> str:
            web_data = gl.nondet.web.render(resolution_url, mode="text")
            task = f'''
                Extract the match result for:
                Team 1: {team1}
                Team 2: {team2}
                
                Web content:
                {web_data}
                
                Respond in JSON:
                {{
                    "score": str,
                    "winner": int
                }}
                Only output the JSON.
            '''
            result = gl.nondet.exec_prompt(task, response_format="json")
            return json.dumps(result, sort_keys=True)

        # Verify and parse

        result_json = json.loads(gl.eq_principle.strict_eq(get_match_result))
        return result_json

Key Files in the genlayer-project-boilerplate

The repository contains several files that illustrate non-deterministic web requests and their surrounding infrastructure:

Summary

  • gl.nondet.web.render fetches external page content in text or HTML mode for use inside smart contracts.
  • The equivalence principle (gl.eq_principle.strict_eq) is mandatory to sanitize non-deterministic web and LLM output so validators can reach consensus.
  • The FootballBets contract in contracts/football_bets.py demonstrates the complete fetch-prompt-verify-parse pattern.
  • Always force a structured response format such as response_format="json" when calling gl.nondet.exec_prompt to simplify downstream parsing.

Frequently Asked Questions

What does gl.nondet.web.render return?

The method returns raw page content for a given URL in either text or HTML form based on the mode parameter. When mode="text" is supplied, HTML tags are stripped so the output can be fed directly into an LLM prompt.

Why is the equivalence principle required for web requests?

Web pages and LLM responses are non-deterministic and may vary across validators. GenLayer uses equivalence-principle functions such as gl.eq_principle.strict_eq to ensure all validators agree on the exact same output before it is recorded on-chain.

Can gl.nondet.web.render fetch HTML instead of text?

Yes. According to the GenLayer API as implemented in the boilerplate, gl.nondet.web.render supports both text and HTML retrieval modes. The FootballBets contract uses mode="text" because plain text is easier to parse inside LLM prompts.

Where is the FootballBets contract located?

The complete implementation is located in contracts/football_bets.py within the genlayer-project-boilerplate repository. This file demonstrates the _check_match method combining gl.nondet.web.render, gl.nondet.exec_prompt, and gl.eq_principle.strict_eq to resolve match results.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →