Building a DoorDash Restaurant Recommender with Hyperbrowser and GPT-4o

In this cookbook, we'll build an intelligent agent that can analyze your DoorDash order history and recommend new restaurants based on your preferences. Our agent will:

  1. Access your DoorDash order history
  2. Analyze past orders including restaurant names, ratings, items ordered, and costs
  3. Determine your food preferences and patterns
  4. Recommend a new cuisine to try based on your ordering habits
  5. Find specific restaurants serving that cuisine

This approach combines:

  • Hyperbrowser for accessing DoorDash data with user authentication
  • OpenAI's GPT-4o for preference analysis and personalized recommendations

By the end of this cookbook, you'll have a personalized restaurant recommendation engine that helps you discover new cuisines and dining experiences!

Prerequisites

To follow along, you'll need the following:

  1. A Hyperbrowser API key (sign up at hyperbrowser.ai if you don't have one)
  2. An OpenAI API key (sign up at openai.com if you don't have one)
  3. A DoorDash account with order history

Both API keys should be stored in a .env file in the same directory as this notebook with the following format:

HYPERBROWSER_API_KEY=your_hyperbrowser_key_here
OPENAI_API_KEY=your_openai_key_here

Step 1: Import Libraries and Initialize Environment

First, we'll import necessary packages and initialize our API clients. We're using:

  • asyncio for asynchronous operations
  • hyperbrowser for web automation and data extraction
  • openai for AI-powered analysis and recommendations
  • pydantic for data modeling and validation
  • IPython.display for formatted output in the notebook
import os
from dotenv import load_dotenv
from hyperbrowser import AsyncHyperbrowser
from hyperbrowser.models.session import CreateSessionParams, CreateSessionProfile
from hyperbrowser.models.extract import StartExtractJobParams
from openai import AsyncOpenAI
from openai.types.chat import (
ChatCompletionSystemMessageParam,
ChatCompletionUserMessageParam,
)
from typing import List
from pydantic import BaseModel
from IPython.display import Markdown, display
load_dotenv()

Step 2: Initialize API Clients

Next, we create instances of the Hyperbrowser and OpenAI clients using our API keys from environment variables. These clients will handle web automation and AI-powered analysis respectively.

hb = AsyncHyperbrowser(api_key=os.getenv("HYPERBROWSER_API_KEY"))
llm = AsyncOpenAI()

Step 3: Set Up Persistent Browser Profile

We'll use a persistent browser profile to maintain login state with DoorDash. This is important because:

  1. It allows us to access authenticated content like order history
  2. It preserves cookies and session data between requests
  3. It provides a consistent browsing experience for our agent

You'll need to replace the placeholder below with your own profile ID, or uncomment the code to create a new profile.

profile_id = "[Place your profile id here if reusing this notebook]"
### If you are using this notebook for the first time, uncomment the following lines and run them
# profile = await hb.profiles.create()
# print(profile)
# session = await hb.sessions.create(CreateSessionParams(profile=CreateSessionProfile(id=profile.id,persist_changes=True)))
# print(session.live_url)
# profile_id = profile.id

Session Management

If you created a new profile, you also need to stop the active browser session. If that's the case you can uncomment and run the code below.

# await hb.sessions.stop(session.id)

Step 4: Define Data Models and Order History Extraction

Now we'll create data models to structure the information we extract from DoorDash. The main components are:

  1. GetRecentOrderInfo - Models a single order with restaurant name, rating, items, and price
  2. GetRecentOrderInfoList - A container for multiple orders
  3. get_orders_list() function - Extracts order history from DoorDash

Using structured data models with Pydantic ensures type safety and makes our data easier to work with.

class GetRecentOrderInfo(BaseModel):
place_name: str
rating: float
food_ordered: List[str]
order_price: float
def __str__(self):
return f"{self.place_name} - {self.rating} - {', '.join(self.food_ordered)} - {self.order_price}"
class GetRecentOrderInfoList(BaseModel):
orders: List[GetRecentOrderInfo]
def __str__(self) -> str:
return "\n".join([str(order) for order in self.orders])
ORDER_LIST_SYSTEM_PROMPT = """
You are a super judgemental food critic. You are required to get my most recent doordash orders and provide a list of restaurants that I have recently ordered from.
In summary
- Find what places I order from on doordash. You will get the
- Place name
- Rating given
- Food ordered
- Price paid
""".strip()
async def get_orders_list():
orders_page = await hb.extract.start_and_wait(
StartExtractJobParams(
urls=["https://www.doordash.com/orders"],
schema=GetRecentOrderInfoList,
session_options=CreateSessionParams(
profile=CreateSessionProfile(id=profile_id)
),
)
)
orders_page_content = GetRecentOrderInfoList.model_validate(orders_page.data)
return orders_page_content

Step 5: Implement Cuisine Recommendation Logic

Based on your order history, our agent needs to recommend a cuisine to try next. This function:

  1. Takes the list of past orders as input
  2. Uses GPT-4o with a specialized system prompt to analyze your ordering patterns
  3. Determines if you prefer variety or consistency in your food choices
  4. Recommends a single cuisine that matches your pattern but introduces something new

The cuisine recommendation is structured as a simple Pydantic model with just the cuisine name.

CUISINE_RECOMMENDATIONS_SYSTEM_PROMPT = """
You are a super judgemental food critic. You are required to analyze my most recent doordash orders which will contain the place name, rating, ordered items, and cost. Given a list of such orders, you are required to recommend me a single cuisine that I should order next. Make your decision based on if I am more experimental, varied, or consistent
"""
class Recommendation(BaseModel):
name: str
async def get_recommended_cuisine(orders_list: GetRecentOrderInfoList):
response = await llm.beta.chat.completions.parse(
messages=[
ChatCompletionSystemMessageParam(
role="system",
content=CUISINE_RECOMMENDATIONS_SYSTEM_PROMPT,
),
ChatCompletionUserMessageParam(
role="user", content=f"Here is the list of orders done {(orders_list)}"
),
],
response_format=Recommendation,
model="gpt-4o",
max_completion_tokens=8000,
)
return response.choices[0].message.parsed

Step 6: Create System Prompt for Restaurant Recommendations

Once we have a recommended cuisine, we need a system prompt that guides the AI in finding specific restaurants. This prompt combines:

  1. Your past order history (to understand your preferences)
  2. The recommended cuisine (to focus the search)
  3. Instructions for formatting the recommendations

The prompt establishes the AI as a "judgemental taste critic" to encourage high-quality, opinionated recommendations.

SYSTEM_PROMPT = """
You are a super judgemental taste critic. You will be given a summary of my most recent orders, including their the place name, rating, ordered items, and cost. You will also be given a cuisine that I have been recommended {cuisine}. From this, you are required to extract structured data from a doordash search and recommend me a place to order from, along with a list of alternate places to that. Recent orders:\n {orders}
""".strip()

Step 7: Define Restaurant Recommendation Data Models and Function

Next, we create models for restaurant recommendations and a function to get those recommendations. The structure includes:

  1. Recommendation - A single restaurant with name and DoorDash link
  2. GetRecommendationInfo - Contains primary and alternative recommendations
  3. get_recommendations() function - Uses Hyperbrowser to extract recommendations from DoorDash

The function combines the system prompt with your order history and recommended cuisine to generate personalized restaurant suggestions.

class Recommendation(BaseModel):
name: str
link: str
class GetRecommendationInfo(BaseModel):
primary_recommendation: Recommendation
other_recommendations: List[Recommendation]
async def get_recommendations(
recent_orders: GetRecentOrderInfoList, recommmended_cuisine: str
):
orders_page = await hb.extract.start_and_wait(
StartExtractJobParams(
urls=["https://www.doordash.com/orders"],
schema=GetRecommendationInfo,
system_prompt=SYSTEM_PROMPT.format(
cuisine=recommmended_cuisine, orders=str(recent_orders)
),
session_options=CreateSessionParams(
profile=CreateSessionProfile(id=profile_id)
),
)
)
orders_page_content = GetRecommendationInfo.model_validate(orders_page.data)
return orders_page_content

Step 8: Format Recommendations for Display

After getting restaurant recommendations, we need to format them attractively for display. This function:

  1. Takes the raw recommendation data and recommended cuisine
  2. Uses a specialized system prompt to guide the formatting
  3. Leverages GPT-4o-mini for efficient text generation
  4. Returns beautifully formatted recommendations ready for display

We're using a smaller language model here (GPT-4o-mini) since this is a simple formatting task that doesn't require the full capabilities of the larger model.

RECOMMENDATION_FORMATTED_SYSTEM_PROMPT = """
You are given a place that was recommended to me on doordash: {primary_recommendation}
Along with this you are given a list of alternate recommendations on doordash: {alternate_recommendations}.
Here is the cuisine I was recommended {cuisine}. Your task is to format it an aesthetically pleasing way to the user.
"""
async def format_recommendation(recommendation: GetRecommendationInfo, cuisine: str):
formatted_system_prompt = RECOMMENDATION_FORMATTED_SYSTEM_PROMPT.format(
primary_recommendation=recommendation.primary_recommendation,
alternate_recommendations=recommendation.other_recommendations,
cuisine=cuisine,
)
repsonse = await llm.chat.completions.create(
messages=[
ChatCompletionSystemMessageParam(
role="system", content=formatted_system_prompt
)
],
model="gpt-4o-mini",
)
return repsonse.choices[0].message.content

Step 9: Bring It All Together - The Complete Restaurant Recommendation Pipeline

Finally, we combine all the previous steps into a complete pipeline that:

  1. Gets your DoorDash order history
  2. Analyzes your ordering patterns to recommend a cuisine
  3. Finds restaurants serving that cuisine
  4. Formats the recommendations into an attractive display

This cell demonstrates the full workflow from data extraction to final presentation.

orders_list = await get_orders_list()
recommened_cuisine = await get_recommended_cuisine(orders_list)
if recommened_cuisine is None or recommened_cuisine.name is None:
raise ValueError("No cuisine recommended")
else:
recommended_locations = await get_recommendations(
recent_orders=orders_list, recommmended_cuisine=recommened_cuisine.name
)
orders_page_content = GetRecommendationInfo.model_validate(recommended_locations)
formatted_recommendation = await format_recommendation(
orders_page_content, recommened_cuisine.name
)
display(Markdown(formatted_recommendation))
🍽️ Peninsula Malaysian Cuisine (Minneapolis)

Alternative Cuisine

  • Cuisine Recommended: Peruvian

Enjoy your meal! If you're looking for more options or specific dishes, feel free to ask.

Conclusion

In this cookbook, we've built a sophisticated restaurant recommendation engine using Hyperbrowser and OpenAI's GPT-4o. Our system:

  1. Extracts and analyzes your DoorDash order history
  2. Identifies patterns in your food preferences
  3. Recommends new cuisines based on your ordering habits
  4. Finds specific restaurants serving those cuisines
  5. Presents recommendations in an attractive, easy-to-read format

This approach combines web automation, data extraction, and AI-powered analysis to create personalized dining recommendations that can help you discover new culinary experiences.

Next Steps

To enhance this system further, you could:

  • Add dietary restriction filtering
  • Incorporate price range preferences
  • Include ratings and reviews from multiple platforms
  • Create a scheduled recommendation system that suggests different meals for different times of day
  • Develop a web or mobile interface for easier interaction

Happy dining!