Em4e commited on
Commit
1ffffd9
Β·
verified Β·
1 Parent(s): d19b508

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +77 -77
app.py CHANGED
@@ -1,46 +1,46 @@
1
- import pandas as pd
2
- import numpy as np
3
- import streamlit as st
4
- import requests
5
-
6
- # ▢️ Use the URL you provided
7
- SAMPLE_FILE_URL = "https://huggingface.co/spaces/Em4e/seo-b2b-saas-forecasting-tool/resolve/main/sample_gsc_data.csv"
8
-
9
- st.set_page_config(page_title="SEO ROI Forecasting Tool for B2B SaaS", layout="wide")
10
- st.title("πŸ“ˆ SEO ROI Forecasting Tool for B2B SaaS")
11
-
12
- st.markdown("""
13
- This app helps you estimate the **financial upside** of ranking improvements for your SEO keywords,
14
- and compare that to what it would cost you in paid ads.
15
- <br>
16
-
17
- πŸ‘‰ **Make sure your CSV has a `CPC` column** (cost per click in $).
18
- If you don’t, we’ll simulate one for you.
19
- <br>
20
-
21
- Developed by: [Emilija Gjorgjevska](https://www.linkedin.com/in/emilijagjorgjevska/)
22
- """, unsafe_allow_html=True)
23
-
24
- +# β€”β€”β€”β€”β€”β€”β€”
25
- +# Download button for the sample file
26
- +sample_bytes = requests.get(SAMPLE_FILE_URL).content
27
- +st.download_button(
28
- + label="πŸ“₯ Download sample CSV",
29
- + data=sample_bytes,
30
- + file_name="sample_gsc_data.csv",
31
- + mime="text/csv",
32
- +)
33
- +# β€”β€”β€”β€”β€”β€”β€”
34
-
35
- # === Sidebar inputs ===
36
- with st.sidebar:
37
- st.header("πŸ”§ Assumptions & Inputs") st.header("πŸ”§ Assumptions & Inputs")
38
- uploaded_file = st.file_uploader("Upload Google Search Console CSV", type="csv")
39
- target_position = st.slider("Target SERP Position", 1.0, 10.0, 4.0, 0.5)
40
- conversion_rate = st.slider("Conversion Rate (% β†’ signup)", 0.1, 10.0, 2.0, 0.1)
41
- close_rate = st.slider("Close Rate (% β†’ customer)", 1.0, 100.0, 20.0, 1.0)
42
- mrr_per_customer = st.slider("MRR per Customer ($)", 10, 1000, 200, 10)
43
- seo_cost = st.slider("Total SEO Investment ($)", 1_000, 100_000, 10_000, 1_000)
44
 
45
  # === Load & prep data ===
46
  def load_csv():
@@ -65,10 +65,10 @@ def calculate_roi(df):
65
  # map and rename
66
  cols = {c.lower(): c for c in df.columns}
67
  need = {
68
- 'query': ['query','keyword','keywords','queries'],
69
  'impressions': ['impressions'],
70
- 'position': ['position','avg. position','average position'],
71
- 'cpc': ['cpc']
72
  }
73
  found = {}
74
  for k, opts in need.items():
@@ -93,8 +93,8 @@ def calculate_roi(df):
93
  return None, pd.DataFrame()
94
 
95
  # compute clicks
96
- df['Current_CTR'] = df.position.apply(get_ctr)
97
- df['Target_CTR'] = get_ctr(target_position)
98
  df['Current_Clicks'] = df.impressions * df.Current_CTR
99
  df['Projected_Clicks'] = df.impressions * df.Target_CTR
100
  df['Incremental_Clicks'] = df.Projected_Clicks - df.Current_Clicks
@@ -104,40 +104,40 @@ def calculate_roi(df):
104
  return None, pd.DataFrame()
105
 
106
  # monetize
107
- conv = conversion_rate / 100
108
  close = close_rate / 100
109
- df['Signups'] = df.Incremental_Clicks * conv
110
- df['Customers'] = df.Signups * close
111
- df['MRR'] = df.Customers * mrr_per_customer
112
 
113
  # paid-ads cost & savings
114
- df['Paid_Cost'] = df.Incremental_Clicks * df.cpc
115
- total_paid_cost = df.Paid_Cost.sum()
116
- savings_vs_paid_ads = total_paid_cost - seo_cost
117
 
118
  # totals & ROI
119
- tot_clicks = df.Incremental_Clicks.sum()
120
- tot_signups = df.Signups.sum()
121
  tot_customers = df.Customers.sum()
122
- tot_mrr = df.MRR.sum()
123
- seo_roi_pct = float('inf') if seo_cost == 0 else ((tot_mrr - seo_cost) / seo_cost) * 100
124
 
125
  summary = {
126
- "clicks": f"{tot_clicks:,.0f}",
127
- "signups": f"{tot_signups:,.1f}",
128
- "customers": f"{tot_customers:,.1f}",
129
- "mrr": f"${tot_mrr:,.2f}",
130
- "roi": f"{seo_roi_pct:,.2f}%",
131
- "paid_cost": f"${total_paid_cost:,.2f}",
132
- "savings": f"${savings_vs_paid_ads:,.2f}"
133
  }
134
 
135
  # table
136
  out = df[['query','MRR','Paid_Cost']].copy()
137
  out.rename(columns={
138
- 'query': 'Keyword',
139
- 'MRR': 'Projected Incremental MRR ($)',
140
- 'Paid_Cost': 'Equivalent Paid Ads Cost ($)'
141
  }, inplace=True)
142
  out['Impact'] = pd.cut(
143
  out['Projected Incremental MRR ($)'],
@@ -155,13 +155,13 @@ if st.button("Run Forecast"):
155
  summary, table = calculate_roi(df)
156
  if summary:
157
  c1, c2, c3, c4, c5, c6, c7 = st.columns(7)
158
- c1.metric("Incremental Clicks", summary['clicks'])
159
- c2.metric("Projected Signups", summary['signups'])
160
- c3.metric("New Customers", summary['customers'])
161
- c4.metric("Incremental MRR", summary['mrr'])
162
- c5.metric("SEO ROI", summary['roi'])
163
- c6.metric("Paid Ads Cost", summary['paid_cost'])
164
- c7.metric("Savings vs Paid Ads", summary['savings'])
165
 
166
  st.subheader("πŸ“Š Opportunity Keywords")
167
- st.dataframe(table, use_container_width=True)
 
1
+ import pandas as pd
2
+ import numpy as np
3
+ import streamlit as st
4
+ import requests
5
+
6
+ # ▢️ Use the URL you provided
7
+ SAMPLE_FILE_URL = "https://huggingface.co/spaces/Em4e/seo-b2b-saas-forecasting-tool/resolve/main/sample_gsc_data.csv"
8
+
9
+ st.set_page_config(page_title="SEO ROI Forecasting Tool for B2B SaaS", layout="wide")
10
+ st.title("πŸ“ˆ SEO ROI Forecasting Tool for B2B SaaS")
11
+
12
+ st.markdown("""
13
+ This app helps you estimate the **financial upside** of ranking improvements for your SEO keywords,
14
+ and compare that to what it would cost you in paid ads.
15
+ <br>
16
+
17
+ πŸ‘‰ **Make sure your CSV has a `CPC` column** (cost per click in $).
18
+ If you don’t, we’ll simulate one for you.
19
+ <br>
20
+
21
+ Developed by: [Emilija Gjorgjevska](https://www.linkedin.com/in/emilijagjorgjevska/)
22
+ """, unsafe_allow_html=True)
23
+
24
+ # β€”β€”β€”β€”β€”β€”β€”
25
+ # Download button for the sample file
26
+ sample_bytes = requests.get(SAMPLE_FILE_URL).content
27
+ st.download_button(
28
+ label="πŸ“₯ Download sample CSV",
29
+ data=sample_bytes,
30
+ file_name="sample_gsc_data.csv",
31
+ mime="text/csv",
32
+ )
33
+ # β€”β€”β€”β€”β€”β€”β€”
34
+
35
+ # === Sidebar inputs ===
36
+ with st.sidebar:
37
+ st.header("πŸ”§ Assumptions & Inputs")
38
+ uploaded_file = st.file_uploader("Upload Google Search Console CSV", type="csv")
39
+ target_position = st.slider("Target SERP Position", 1.0, 10.0, 4.0, 0.5)
40
+ conversion_rate = st.slider("Conversion Rate (% β†’ signup)", 0.1, 10.0, 2.0, 0.1)
41
+ close_rate = st.slider("Close Rate (% β†’ customer)", 1.0, 100.0, 20.0, 1.0)
42
+ mrr_per_customer = st.slider("MRR per Customer ($)", 10, 1000, 200, 10)
43
+ seo_cost = st.slider("Total SEO Investment ($)", 1_000, 100_000, 10_000, 1_000)
44
 
45
  # === Load & prep data ===
46
  def load_csv():
 
65
  # map and rename
66
  cols = {c.lower(): c for c in df.columns}
67
  need = {
68
+ 'query': ['query','keyword','keywords','queries'],
69
  'impressions': ['impressions'],
70
+ 'position': ['position','avg. position','average position'],
71
+ 'cpc': ['cpc']
72
  }
73
  found = {}
74
  for k, opts in need.items():
 
93
  return None, pd.DataFrame()
94
 
95
  # compute clicks
96
+ df['Current_CTR'] = df.position.apply(get_ctr)
97
+ df['Target_CTR'] = get_ctr(target_position)
98
  df['Current_Clicks'] = df.impressions * df.Current_CTR
99
  df['Projected_Clicks'] = df.impressions * df.Target_CTR
100
  df['Incremental_Clicks'] = df.Projected_Clicks - df.Current_Clicks
 
104
  return None, pd.DataFrame()
105
 
106
  # monetize
107
+ conv = conversion_rate / 100
108
  close = close_rate / 100
109
+ df['Signups'] = df.Incremental_Clicks * conv
110
+ df['Customers'] = df.Signups * close
111
+ df['MRR'] = df.Customers * mrr_per_customer
112
 
113
  # paid-ads cost & savings
114
+ df['Paid_Cost'] = df.Incremental_Clicks * df.cpc
115
+ total_paid_cost = df.Paid_Cost.sum()
116
+ savings_vs_paid_ads = total_paid_cost - seo_cost
117
 
118
  # totals & ROI
119
+ tot_clicks = df.Incremental_Clicks.sum()
120
+ tot_signups = df.Signups.sum()
121
  tot_customers = df.Customers.sum()
122
+ tot_mrr = df.MRR.sum()
123
+ seo_roi_pct = float('inf') if seo_cost == 0 else ((tot_mrr - seo_cost) / seo_cost) * 100
124
 
125
  summary = {
126
+ "clicks": f"{tot_clicks:,.0f}",
127
+ "signups": f"{tot_signups:,.1f}",
128
+ "customers": f"{tot_customers:,.1f}",
129
+ "mrr": f"${tot_mrr:,.2f}",
130
+ "roi": f"{seo_roi_pct:,.2f}%",
131
+ "paid_cost": f"${total_paid_cost:,.2f}",
132
+ "savings": f"${savings_vs_paid_ads:,.2f}"
133
  }
134
 
135
  # table
136
  out = df[['query','MRR','Paid_Cost']].copy()
137
  out.rename(columns={
138
+ 'query': 'Keyword',
139
+ 'MRR': 'Projected Incremental MRR ($)',
140
+ 'Paid_Cost': 'Equivalent Paid Ads Cost ($)'
141
  }, inplace=True)
142
  out['Impact'] = pd.cut(
143
  out['Projected Incremental MRR ($)'],
 
155
  summary, table = calculate_roi(df)
156
  if summary:
157
  c1, c2, c3, c4, c5, c6, c7 = st.columns(7)
158
+ c1.metric("Incremental Clicks", summary['clicks'])
159
+ c2.metric("Projected Signups", summary['signups'])
160
+ c3.metric("New Customers", summary['customers'])
161
+ c4.metric("Incremental MRR", summary['mrr'])
162
+ c5.metric("SEO ROI", summary['roi'])
163
+ c6.metric("Paid Ads Cost", summary['paid_cost'])
164
+ c7.metric("Savings vs Paid Ads", summary['savings'])
165
 
166
  st.subheader("πŸ“Š Opportunity Keywords")
167
+ st.dataframe(table, use_container_width=True)