Web Access
Web Access lets Intelligent Contracts fetch external data, send HTTP requests, render web pages, capture screenshots, and handle API errors from non-deterministic blocks. Because leaders and validators make independent web requests, use stable fields or derived summaries when applying the Equivalence Principle to web data.
HTTP Requests
Send data to external services:
def post_request():
url = "https://test-server.genlayer.com/body/echo"
response = gl.nondet.web.request(
url,
method='POST',
body={}
)
return response.status_code
status_code = gl.eq_principle.strict_eq(post_request)Web Rendering
Render web page and extract content:
def render_page():
url = "https://test-server.genlayer.com/static/genvm/hello.html"
# Render HTML content
html_content = gl.nondet.web.render(url, mode='html')
return html_content
page_html = gl.eq_principle.strict_eq(render_page)Screenshot Capture
Take screenshots of web pages:
def take_screenshot():
url = "https://test-server.genlayer.com/static/genvm/hello.html"
# Capture page as image
screenshot = gl.nondet.web.render(url, mode='screenshot')
return screenshot
image_data = gl.eq_principle.strict_eq(take_screenshot)Handling HTTP Errors
External APIs can return error responses. Consider checking the status code:
def fetch_data():
response = gl.nondet.web.request(api_url, method='GET')
if response.status_code >= 400 and response.status_code < 500:
raise gl.UserError(f"API returned client error: {response.status_code}")
elif response.status_code >= 500:
raise gl.UserError(f"API temporarily unavailable: {response.status_code}")
return json.loads(response.body.decode("utf-8"))Consensus-Friendly Web Requests
When using web data in non-deterministic blocks, remember that the leader and validators make independent requests. External APIs may return different data between calls — timestamps change, counts update, caches vary.
Extract Stable Fields
One approach is to return only the fields that won't change between calls:
def leader_fn():
res = gl.nondet.web.get(api_url)
data = json.loads(res.body.decode("utf-8"))
# Only return fields that are stable across requests
return {"id": data["id"], "login": data["login"], "status": data["status"]}
# NOT: follower_count, updated_at, online_statusDerive Status from Variable Data
When raw data may differ between leader and validator (e.g., CI check counts change), consider comparing a derived summary instead of the raw values:
def validator_fn(leaders_res: gl.vm.Result) -> bool:
validator_data = leader_fn()
def derive_status(checks):
if not checks:
return "pending"
for c in checks:
if c.get("conclusion") != "success":
return "failing"
return "success"
return derive_status(leaders_res.calldata) == derive_status(validator_data)See the Equivalence Principle page for more validation patterns.