Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.nimbleway.com/llms.txt

Use this file to discover all available pages before exploring further.

Bring Nimble’s web data into Snowflake as native SQL procedures, then wire them into a Cortex Agent so any Snowflake Intelligence chat (or any caller of the agent run REST API) can search the web and pull live page content alongside your warehouse data.

What you get

  • NIMBLE_SEARCH and NIMBLE_EXTRACT callable from any Snowflake SQL. Pipelines, notebooks, Streamlit, dbt.
  • A pre-built Cortex Agent wired to those tools, invocable from Snowflake Intelligence or the agent run REST API
  • Stays inside your Snowflake account. Only authorized outbound calls hit Nimble.
  • One-time setup, run by ACCOUNTADMIN. Under 5 minutes.

Prerequisites

  • ACCOUNTADMIN role
  • Snowflake Enterprise edition or higher
  • A Nimble API key (sign up free)

Install Nimble in Snowflake

1

Create the role, database, and dedicated warehouse

Set up an isolated namespace for the integration. A dedicated warehouse keeps agent traffic separate from analytics workloads and makes cost attribution trivial.
USE ROLE ACCOUNTADMIN;

CREATE ROLE IF NOT EXISTS nimble_role;
GRANT DATABASE ROLE SNOWFLAKE.CORTEX_USER TO ROLE nimble_role;

CREATE DATABASE IF NOT EXISTS NIMBLE_INTEGRATION;
CREATE SCHEMA   IF NOT EXISTS NIMBLE_INTEGRATION.TOOLS;
GRANT USAGE ON DATABASE NIMBLE_INTEGRATION       TO ROLE nimble_role;
GRANT USAGE ON SCHEMA   NIMBLE_INTEGRATION.TOOLS TO ROLE nimble_role;

CREATE WAREHOUSE IF NOT EXISTS NIMBLE_AGENT_WH
  WAREHOUSE_SIZE = XSMALL
  AUTO_SUSPEND   = 60
  AUTO_RESUME    = TRUE;
GRANT USAGE ON WAREHOUSE NIMBLE_AGENT_WH TO ROLE nimble_role;

cookbook/snowflake/01_setup.sql

Full setup script: role, grants, database, schema, warehouse
2

Authorize outbound traffic to Nimble

Create a network rule, store your Nimble API key as a Snowflake secret, and bind both into an External Access Integration. Stored procedures must reference the EAI to make outbound HTTPS calls.
CREATE OR REPLACE NETWORK RULE nimble_api_rule
  MODE       = EGRESS
  TYPE       = HOST_PORT
  VALUE_LIST = ('sdk.nimbleway.com:443');

CREATE OR REPLACE SECRET nimble_api_key
  TYPE          = GENERIC_STRING
  SECRET_STRING = 'YOUR_NIMBLE_API_KEY';

CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION nimble_eai
  ALLOWED_NETWORK_RULES          = (nimble_api_rule)
  ALLOWED_AUTHENTICATION_SECRETS = (nimble_api_key)
  ENABLED                        = TRUE;

GRANT USAGE ON INTEGRATION nimble_eai TO ROLE nimble_role;

cookbook/snowflake/01_setup.sql

Network rule, secret, and External Access Integration block
3

Deploy NIMBLE_SEARCH

A Python stored procedure that calls Nimble’s Search API and returns the raw JSON response as a STRING. The caller uses PARSE_JSON() to navigate results.
CREATE OR REPLACE PROCEDURE NIMBLE_INTEGRATION.TOOLS.NIMBLE_SEARCH(
  query        STRING,
  num_results  INTEGER DEFAULT 10
)
RETURNS STRING
LANGUAGE PYTHON
RUNTIME_VERSION = 3.11
PACKAGES        = ('requests')
HANDLER         = 'run'
EXTERNAL_ACCESS_INTEGRATIONS = (nimble_eai)
SECRETS         = ('api_key' = nimble_api_key)
AS $$
import json, _snowflake, requests

def run(session, query, num_results):
    key = _snowflake.get_generic_secret_string('api_key')
    r = requests.post(
        'https://sdk.nimbleway.com/v1/search',
        headers={'Authorization': f'Bearer {key}',
                 'Content-Type':  'application/json'},
        json={'query': query, 'parse': True, 'num_results': num_results},
        timeout=60,
    )
    r.raise_for_status()
    return json.dumps(r.json())
$$;

GRANT USAGE ON PROCEDURE NIMBLE_INTEGRATION.TOOLS.NIMBLE_SEARCH(STRING, INTEGER)
  TO ROLE nimble_role;

cookbook/snowflake/02_nimble_search.sql

Full procedure with error handling and pagination
4

Deploy NIMBLE_EXTRACT

Same shape as NIMBLE_SEARCH. Takes a comma-separated list of URLs and returns parsed page content as JSON.
CREATE OR REPLACE PROCEDURE NIMBLE_INTEGRATION.TOOLS.NIMBLE_EXTRACT(urls STRING)
RETURNS STRING
LANGUAGE PYTHON
RUNTIME_VERSION = 3.11
PACKAGES        = ('requests')
HANDLER         = 'run'
EXTERNAL_ACCESS_INTEGRATIONS = (nimble_eai)
SECRETS         = ('api_key' = nimble_api_key)
AS $$
import json, _snowflake, requests

def run(session, urls):
    key = _snowflake.get_generic_secret_string('api_key')
    out = []
    for u in [x.strip() for x in urls.split(',') if x.strip()]:
        r = requests.post(
            'https://sdk.nimbleway.com/v1/extract',
            headers={'Authorization': f'Bearer {key}',
                     'Content-Type':  'application/json'},
            json={'url': u, 'parse': True},
            timeout=60,
        )
        r.raise_for_status()
        out.append(r.json())
    return json.dumps(out)
$$;

GRANT USAGE ON PROCEDURE NIMBLE_INTEGRATION.TOOLS.NIMBLE_EXTRACT(STRING)
  TO ROLE nimble_role;

cookbook/snowflake/03_nimble_extract.sql

Full procedure with batching and retry
5

Register the Cortex Agent

Wire both procedures into a Cortex Agent. tool_spec.type: generic declares each tool’s JSON schema; tool_resources maps the schema to the underlying procedure and the warehouse that runs it.
CREATE OR REPLACE AGENT nimble_web_research_agent
  COMMENT = 'Agent with Nimble web search and content retrieval'
  FROM SPECIFICATION
  $$
  models:
    orchestration: auto

  orchestration:
    budget:
      seconds: 60
      tokens:  32000

  instructions:
    system: |
      You are a research assistant with access to Nimble's web data toolkit.
      Always cite source URLs.
    orchestration: |
      - Use NIMBLE_SEARCH for queries requiring web search.
      - Use NIMBLE_EXTRACT when the user provides specific URLs.

  tools:
    - tool_spec:
        type: generic
        name: nimble_search
        description: Search the web using Nimble.
        input_schema:
          type: object
          properties:
            query:       { type: string,  description: The search query. }
            num_results: { type: integer, description: "Number of results (default 10)." }
          required: [query]

    - tool_spec:
        type: generic
        name: nimble_extract
        description: Retrieve parsed content for specific URLs.
        input_schema:
          type: object
          properties:
            urls: { type: string, description: Comma-separated URLs. }
          required: [urls]

  tool_resources:
    nimble_search:
      type: procedure
      execution_environment:
        type:      warehouse
        warehouse: NIMBLE_AGENT_WH
      identifier: NIMBLE_INTEGRATION.TOOLS.NIMBLE_SEARCH
    nimble_extract:
      type: procedure
      execution_environment:
        type:      warehouse
        warehouse: NIMBLE_AGENT_WH
      identifier: NIMBLE_INTEGRATION.TOOLS.NIMBLE_EXTRACT
  $$;

cookbook/snowflake/04_cortex_agent.sql

Full agent spec, including grants and verification queries

Try these recipes

Recipe 1: Quick search and extract from SQL

Both procedures return STRING. Use PARSE_JSON() to navigate the response.
CALL NIMBLE_INTEGRATION.TOOLS.NIMBLE_SEARCH('AI agents news', 5);

CALL NIMBLE_INTEGRATION.TOOLS.NIMBLE_EXTRACT(
  'https://docs.snowflake.com/en/user-guide/snowflake-cortex/cortex-agents'
);

SELECT PARSE_JSON(
  NIMBLE_INTEGRATION.TOOLS.NIMBLE_SEARCH('best practices for Cortex Agents', 3)
):results[0]:url::STRING AS top_result_url;

Recipe 2: CPG retailer price and availability monitoring

A CPG brand keeps its product master in Snowflake and wants daily competitive intelligence on how its SKUs appear across Amazon, Walmart, and Target. Nimble Search finds the listing URL per SKU per retailer; Nimble Extract pulls price, stock, and reviews from each listing; the enriched rows land in a PRODUCT_LISTINGS table that BI can read. Input: PRODUCTS
skubrandproduct_nameupccategory
LB-001Liquid DeathMountain Water 16.9oz 12pk810014710013Beverages
OB-014OlipopVintage Cola 12oz 12pk850000334038Beverages
ATH-002Athletic BrewingFree Wave Hazy IPA 12pk850001234567Beverages
Output: PRODUCT_LISTINGS
skuretailerlisting_urlpricecurrencyin_stockratingreview_countlast_seen_at
LB-001amazonhttps://amazon.com/dp/18.99USDTRUE4.7124832026-05-25
LB-001walmarthttps://walmart.com/ip/17.48USDTRUE4.632012026-05-25
LB-001targethttps://target.com/p/A-17.99USDFALSE4.89422026-05-25
A v_price_alerts view layers on top, surfacing SKUs with a 10%+ price drop versus the trailing seven-day median (or any retailer flipping to out-of-stock), and feeds the daily competitive briefing.

cookbook/snowflake/recipes/cpg_price_monitoring/

Full recipe: sample data, enrichment SQL, the alerts view, and the daily task

Recipe 3: Chat with the agent in Snowflake Intelligence

The fastest way to try the agent is the Snowflake Intelligence UI:
1

Open Snowflake Intelligence

From Snowsight, open AI & ML → Snowflake Intelligence.
2

Pick the agent

Select NIMBLE_WEB_RESEARCH_AGENT from the agent picker. The two tools (nimble_search, nimble_extract) appear in the tool tray.
3

Ask a research question

Try a prompt that forces both tools. For example: “Find the three most recent posts on Snowflake’s engineering blog about Cortex, then pull the full text of each.” The agent calls nimble_search, picks URLs from the results, then calls nimble_extract to retrieve page content, and answers with citations.
Need to call the agent programmatically? The same agent is reachable via the Cortex Agents REST API: POST to /api/v2/databases/{db}/schemas/{schema}/agents/NIMBLE_WEB_RESEARCH_AGENT:run with a message body. Useful for Streamlit apps, scheduled tasks, or wiring the agent into an external orchestrator.

Recipe 4: Schedule recurring enrichment

Wrap the CPG enrichment in a Snowflake task so it runs every morning before the business day. The task uses the same NIMBLE_AGENT_WH warehouse and writes incrementally to PRODUCT_LISTINGS.
CREATE OR REPLACE TASK refresh_product_listings
  WAREHOUSE = NIMBLE_AGENT_WH
  SCHEDULE  = 'USING CRON 0 6 * * * UTC'
AS
  CALL NIMBLE_INTEGRATION.RECIPES.REFRESH_PRODUCT_LISTINGS();

ALTER TASK refresh_product_listings RESUME;

cookbook/snowflake/recipes/cpg_price_monitoring/schedule.sql

Full scheduled task: incremental load, retry policy, and dead-letter handling

Roll out across your organization

  • Grant scoped access. Grant nimble_role to the specific user roles or service accounts that should call the procedures, not to PUBLIC. The role already carries SNOWFLAKE.CORTEX_USER, so grantees can invoke the agent without any extra Cortex grant.
  • Tune for your Nimble rate-limit tier. The cookbook enrichment proc accepts a max_workers parameter for concurrent extraction. Start at 4 and raise it as your tier allows; Nimble’s rate-limits page lists per-tier ceilings.
  • Right-size the warehouse. XSMALL with 60-second auto-suspend is fine for interactive agent chat. For large batch enrichment (thousands of SKUs), step up to SMALL or MEDIUM only for the duration of the scheduled task; suspend cost is negligible at this size.
  • Contain cost during dev. Use TABLESAMPLE on the source table when iterating on enrichment logic, and monitor spend via the TASK_HISTORY and WAREHOUSE_METERING_HISTORY views.
  • Pre-approve the agent in shared workspaces. When sharing Snowflake Intelligence workspaces, add NIMBLE_WEB_RESEARCH_AGENT to the workspace’s allowed agent list so collaborators can invoke it without re-granting access.

Resources

Nimbleway/cookbook (snowflake/)

Every SQL file referenced on this page, plus the CPG recipe

Nimble Search API

Request shape, parameters, and response schema for NIMBLE_SEARCH

Nimble Extract API

Request shape, parameters, and response schema for NIMBLE_EXTRACT

Snowflake External Access Integration

How Snowflake gates outbound HTTPS from stored procedures

Snowflake Cortex Agents

Overview of the Cortex Agents runtime and orchestration model

CREATE AGENT reference

Full SQL reference for the agent spec used in Step 5