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:
- Access your DoorDash order history
- Analyze past orders including restaurant names, ratings, items ordered, and costs
- Determine your food preferences and patterns
- Recommend a new cuisine to try based on your ordering habits
- 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:
- A Hyperbrowser API key (sign up at hyperbrowser.ai if you don't have one)
- An OpenAI API key (sign up at openai.com if you don't have one)
- 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 operationshyperbrowser
for web automation and data extractionopenai
for AI-powered analysis and recommendationspydantic
for data modeling and validationIPython.display
for formatted output in the notebook
import osfrom dotenv import load_dotenvfrom hyperbrowser import AsyncHyperbrowserfrom hyperbrowser.models.session import CreateSessionParams, CreateSessionProfilefrom hyperbrowser.models.extract import StartExtractJobParamsfrom openai import AsyncOpenAIfrom openai.types.chat import (ChatCompletionSystemMessageParam,ChatCompletionUserMessageParam,)from typing import Listfrom pydantic import BaseModelfrom IPython.display import Markdown, displayload_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:
- It allows us to access authenticated content like order history
- It preserves cookies and session data between requests
- 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:
GetRecentOrderInfo
- Models a single order with restaurant name, rating, items, and priceGetRecentOrderInfoList
- A container for multiple ordersget_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: strrating: floatfood_ordered: List[str]order_price: floatdef __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:
- Takes the list of past orders as input
- Uses GPT-4o with a specialized system prompt to analyze your ordering patterns
- Determines if you prefer variety or consistency in your food choices
- 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: strasync 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:
- Your past order history (to understand your preferences)
- The recommended cuisine (to focus the search)
- 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:
Recommendation
- A single restaurant with name and DoorDash linkGetRecommendationInfo
- Contains primary and alternative recommendationsget_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: strlink: strclass GetRecommendationInfo(BaseModel):primary_recommendation: Recommendationother_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:
- Takes the raw recommendation data and recommended cuisine
- Uses a specialized system prompt to guide the formatting
- Leverages GPT-4o-mini for efficient text generation
- 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:
- Gets your DoorDash order history
- Analyzes your ordering patterns to recommend a cuisine
- Finds restaurants serving that cuisine
- 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))
Recommended Restaurant
🍽️ Peninsula Malaysian Cuisine (Minneapolis)
-
Cuisine: Malaysian
-
Link: Order Here
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:
- Extracts and analyzes your DoorDash order history
- Identifies patterns in your food preferences
- Recommends new cuisines based on your ordering habits
- Finds specific restaurants serving those cuisines
- 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!