A simple and powerful platform for conducting streetscape perception surveys with image-based questions. Deploy in minutes with Supabase and Vercel.
π Live Demo: https://streetscape-perception-survey.vercel.app/
This platform was initially developed for the Thermal Affordance research, which introduces a novel framework for assessing urban thermal comfort using street view imagery and human perception surveys.
- Create Account: Go to supabase.com and create a free account
- Create Project: Click "New Project" and create a project
- Setup Database: Go to SQL Editor and run this script to create your database:
-- Create survey responses table
CREATE TABLE survey_responses (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
participant_id TEXT,
responses JSONB NOT NULL,
displayed_images JSONB,
survey_metadata JSONB,
completed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Create images table for managing street view images
CREATE TABLE street_images (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
filename TEXT NOT NULL,
url TEXT NOT NULL,
description TEXT,
category TEXT,
active BOOLEAN DEFAULT true
);
-- Enable Row Level Security
ALTER TABLE survey_responses ENABLE ROW LEVEL SECURITY;
ALTER TABLE street_images ENABLE ROW LEVEL SECURITY;
-- Create policies for public access (adjust as needed)
CREATE POLICY "Allow public insert" ON survey_responses FOR INSERT WITH CHECK (true);
CREATE POLICY "Allow public select" ON street_images FOR SELECT USING (active = true);
-
Get API Keys: Go to Settings β API Keys and Data API panels, and copy your:
- Project URL
- Anon public key
πΎ Save these for later use - you'll need them in Step 3!
-
Create Storage: In Supabase, go to Storage
-
Create Bucket: Create a new bucket called
street-images
, and make it a public bucket. -
Upload Images: Upload your street view images to this bucket
-
Get Folder Base URL: Your images folder base URL is:
https://your-project.supabase.co/storage/v1/object/public/street-images/
Individual images will be:
https://your-project.supabase.co/storage/v1/object/public/street-images/filename.jpg
πΎ Save this folder base URL - you'll need it in Step 3!
- Clone and Install:
git clone https://github.com/yourusername/streetscape-perception-survey.git
cd streetscape-perception-survey
./deploy.sh
- Add Credentials: The script will create
.env.local
- edit it with your Supabase credentials:
REACT_APP_SUPABASE_URL=https://your-project.supabase.co
REACT_APP_SUPABASE_ANON_KEY=your-anon-key
β οΈ IMPORTANT: Configure Your Images: Editsrc/config/streetImages.js
and MUST REPLACE with your own data:
// π§ STEP 1: Replace with YOUR Supabase project URL
const SUPABASE_STORAGE_URL = "https://YOUR-PROJECT-ID.supabase.co/storage/v1/object/public/street-images";
// π§ STEP 2: Replace with YOUR actual image filenames
const imageFilenames = [
"your_street_image_1.jpg",
"your_street_image_2.jpg",
"your_street_image_3.jpg",
"your_street_image_4.jpg",
// Add ALL your uploaded image filenames here...
];
π¨ CRITICAL: You MUST replace both:
YOUR-PROJECT-ID
with your actual Supabase project ID- The image filenames with your actual uploaded image names
π Quick way to get all filenames: After uploading images to Supabase Storage, you can:
- In Supabase Storage, select all your images and copy the filenames
- Or use this command in your terminal to list all files:
ls your_images_folder/
- Or in Supabase Storage interface, you can see all filenames in the file list
- Customize Survey (optional):
- Edit
src/config/surveyConfig.js
to change title, description, and lab information - Edit
src/config/questions.js
to modify questions
- Edit
- Push to GitHub:
git add .
git commit -m "Initial setup"
git push origin main
- Deploy: Go to vercel.com and sign up
- Import Project: Click "New Project" and import your GitHub repository
- Add Environment Variables: In Vercel project settings, add these environment variables:
- Name:
REACT_APP_SUPABASE_URL
, Value:https://your-project.supabase.co
- Name:
REACT_APP_SUPABASE_ANON_KEY
, Value:your-anon-key-here
- Name:
- Deploy: Click Deploy
π Your survey will be live at https://your-project.vercel.app
- Go to your Supabase dashboard
- Navigate to Table Editor β survey_responses
- View all responses in real-time
- Export data as CSV for analysis
This survey platform was initially developed for the following research:
@article{yang2025thermal,
title={Thermal comfort in sight: Thermal affordance and its visual assessment for sustainable streetscape design},
author={Yang, Sijie and Chong, Adrian and Liu, Pengyuan and Biljecki, Filip},
journal={Building and Environment},
pages={112569},
year={2025},
publisher={Elsevier}
}
If you use this platform in your research, please consider citing the above paper.
Edit src/config/surveyConfig.js
:
export const surveyConfig = {
title: "Your Survey Title",
description: "Your survey description...",
logo: "https://your-supabase-url/storage/v1/object/public/street-images/lab-logo.jpg",
labDescription: "Your lab description...",
// ... other settings
};
All survey questions are configured in src/config/questions.js
. The system uses pre-generated random images for consistency.
Images are pre-generated when the survey loads using this logic:
const displayedImages = {
safety_perception: getRandomImages("safety_perception", 2), // 2 images, choose 1
attractiveness_perception: getRandomImages("attractiveness_perception", 2), // 2 images, choose 1
liveliness_perception: getRandomImages("liveliness_perception", 4), // 4 images, choose 1
// ... more questions
};
Current example: Safety perception question
{
type: "imagepicker",
name: "safety_perception",
title: "Safety Perception",
description: "Which street environment do you perceive to be the SAFEST?",
choices: displayedImages.safety_perception, // Uses pre-generated images
multiSelect: false
}
To modify:
- Change the question text: Edit
title
anddescription
- Change number of images: Modify the count in
generateQuestionImages()
:safety_perception: getRandomImages("safety_perception", 4), // Change 2 to 4 for more options
- Change perception type: Replace "safety_perception" with your own (e.g., "beauty_perception")
- Add new image question: Add both in
generateQuestionImages()
and in the survey page
π¨ IMPORTANT: Current survey has 6 perception questions:
safety_perception
(2 choose 1) - Which street is SAFEST?attractiveness_perception
(2 choose 1) - Which street is most ATTRACTIVE?walkability_perception
(2 choose 1) - Which street is most WALKABLE?liveliness_perception
(4 choose 1) - Which street is most LIVELY?relaxation_perception
(4 choose 1) - Which street is most RELAXING?cleanliness_perception
(4 choose 1) - Which street is most CLEAN?
Current example: Comfort rating
{
type: "image",
name: "comfort_image",
imageLink: displayedImages.comfort_rating[0]?.imageLink, // Shows 1 random image
},
{
type: "radiogroup",
name: "comfort_level",
title: "How comfortable would you feel walking in this street?",
choices: [
{ value: 1, text: "Very Uncomfortable" },
{ value: 2, text: "Uncomfortable" },
{ value: 3, text: "Neutral" },
{ value: 4, text: "Comfortable" },
{ value: 5, text: "Very Comfortable" }
]
}
To modify:
- Change the question: Edit
title
- Change scale labels: Modify the
choices
array text - Change scale range: Add/remove choice options (e.g., 1-7 scale)
- Ensure image is generated: Make sure
comfort_rating
is ingenerateQuestionImages()
Current example: Age demographics
{
name: "age",
title: "What is your age group?",
type: "radiogroup",
choices: [
{ value: "18-24", text: "18-24 years old" },
{ value: "25-34", text: "25-34 years old" },
{ value: "35-44", text: "35-44 years old" },
// ... more options
]
}
To modify:
- Change
title
to your question - Replace
choices
array with your options - Each choice needs
value
(data saved) andtext
(displayed)
Current example: Street elements identification
{
type: "image",
name: "elements_image",
imageLink: displayedImages.street_elements[0]?.imageLink, // Shows 1 random image
},
{
type: "checkbox",
name: "visible_elements",
title: "Which elements do you notice in this street? (Select all that apply)",
choices: [
"Trees and vegetation",
"Street furniture (benches, lights)",
"Bicycle lanes",
"Pedestrian crossings",
"Public art or decorations",
// ... more options
]
}
To modify:
- Change the question: Edit
title
- Change options: Replace
choices
array with your options - Ensure image is generated: Make sure
street_elements
is ingenerateQuestionImages()
Current example: Feature importance ranking
{
type: "image",
name: "ranking_image",
imageLink: displayedImages.feature_ranking[0]?.imageLink, // Shows 1 random image
},
{
type: "ranking",
name: "street_features",
title: "Based on the image above, drag to rank these features from most important (top) to least important (bottom):",
choices: [
{ value: "safety", text: "Safety and security" },
{ value: "greenery", text: "Trees and greenery" },
{ value: "walkability", text: "Wide sidewalks and walkability" },
{ value: "aesthetics", text: "Visual appeal and aesthetics" },
{ value: "amenities", text: "Street furniture and amenities" }
]
}
To modify:
- Change the question: Edit
title
- Change ranking items: Replace
choices
array (usevalue
andtext
format) - Ensure image is generated: Make sure
feature_ranking
is ingenerateQuestionImages()
Current example: Additional feedback
{
type: "image",
name: "feedback_image",
imageLink: displayedImages.open_feedback[0]?.imageLink, // Shows 1 random image
},
{
type: "comment",
name: "general_feedback",
title: "Looking at this street, what makes a street environment appealing to you? (Optional)",
description: "Please share your thoughts about streetscape design, walkability, or any other aspects that matter to you.",
maxLength: 500
}
To modify:
- Change the question: Edit
title
anddescription
- Adjust text box: Change
maxLength
or usetype: "text"
for single-line - Ensure image is generated: Make sure
open_feedback
is ingenerateQuestionImages()
To add a completely new image-based question:
Step 1: Add to generateQuestionImages()
:
const questionImages = {
// ... existing questions
your_new_question: getRandomImages("your_new_question", 4), // 4 images to choose from
};
Step 2: Add to the appropriate survey page:
{
type: "imagepicker",
name: "your_new_question",
title: "Your Question Title",
description: "Your question description",
choices: displayedImages.your_new_question,
multiSelect: false // or true for multiple selection
}
Make questions appear based on previous answers:
{
name: "follow_up_question",
title: "Follow-up question",
type: "text",
visibleIf: "{previous_question} = 'specific_answer'"
}
Questions appear in the order they're listed in each page's elements
array. Simply reorder them in the file.
Remove required: true
or set required: false
to make any question optional.
The default survey includes 6 parts:
- Part 1: Demographics (Optional) - Age, location, income, education, outdoor activities
- Part 2: Street Perception (6 questions) - Safety, attractiveness, walkability, liveliness, relaxation, cleanliness
- Part 3: Comfort Rating - 1-5 scale rating with image
- Part 4: Street Elements - Checkbox identification with image
- Part 5: Feature Ranking - Drag & drop ranking with image
- Part 6: Open Feedback - Text input with image
Edit src/styles/globals.css
to match your brand:
- Colors
- Fonts
- Layout spacing
- Component styling
Access your data via Supabase API or dashboard:
- Real-time responses
- CSV export
- JSON format
- Direct database queries
The survey automatically adapts to:
- Desktop computers
- Tablets
- Mobile phones
- Different screen orientations
- No personal data stored by default
- Supabase handles data security
- GDPR compliant
- Optional participant anonymization
- Check Supabase storage bucket is public
- Verify image URLs are correct
- Ensure images are in supported formats (JPG, PNG, WebP)
- Check Supabase connection
- Verify environment variables in
.env.local
- Check browser console for errors
- Ensure all environment variables are set in Vercel
- Check build logs for errors
- Verify GitHub repository is connected
npm install
npm start
Track survey performance:
- Response rates
- Completion times
- Drop-off points
- Device/browser statistics
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
MIT License - feel free to use for research and commercial projects.
- GitHub Issues: Report bugs and request features
- All configuration is in the
src/config/
folder - Check console logs for debugging information
That's it! Your streetscape perception survey is ready to collect responses! π