Context: Searching for a new senior level software development job over a 9 week period in summer 2025.

  • Focused mostly on data engineering and backend roles that are in-person or hybrid in the SF Bay Area.
  • Leads from recruiters on LinkedIn were much more likely to lead to interviews+offers.
  • The winning offer came through my personal network.
  • I mostly used Hiring.cafe for prospecting. They're a scraper with an interface I didn't hate.
Sankey diagram of job search
you are viewing a single comment's thread
view the rest of the comments
[–] 1 point 1 year ago (2 children)

Don't know if there's a ready-made site for stuff like that, but it's not hard to do.

Here's a quick and dirty AI generated piece of trash code as a proof of concept:

# sankey_hiring_funnel_direct.py
# Requires: plotly
# Install: pip install plotly

import plotly.graph_objects as go

# Node labels (unique)
labels = [
    "Network",            # 0
    "Hiring.cafe",        # 1
    "Abandoned Lead",     # 2
    "Applied",            # 3
    "Rejected",           # 4
    "No Response",        # 5
    "Screener",           # 6
    "Rejected by Screen", # 7
    "Full Round",         # 8
    "Rejected by Panel",  # 9
    "Offer",              #10
    "Accepted",           #11
    "Declined"            #12
]

# Colors for the two source groups (consistent)
network_color = "rgba(31,119,180,0.8)"      # blue-ish
hiring_color  = "rgba(255,127,14,0.8)"      # orange-ish

sources = []
targets = []
values  = []
link_colors = []

def add_link(src_idx, tgt_idx, val, color):
    sources.append(src_idx)
    targets.append(tgt_idx)
    values.append(val)
    link_colors.append(color)

# Direct flows from Network and Hiring.cafe into Abandoned Lead and Applied
add_link(0, 2, 1, network_color)    # Network -> Abandoned Lead (1)
add_link(1, 2, 58, hiring_color)    # Hiring.cafe -> Abandoned Lead (58)
add_link(0, 3, 11, network_color)   # Network -> Applied (11)
add_link(1, 3, 70, hiring_color)    # Hiring.cafe -> Applied (70)

# Applied -> Rejected, No Response, Screener (split by original group)
add_link(3, 4, 5, network_color)    # Applied -> Rejected (network 5)
add_link(3, 4, 40, hiring_color)    # Applied -> Rejected (hiring 40)
add_link(3, 5, 3, network_color)    # Applied -> No Response (network 3)
add_link(3, 5, 15, hiring_color)    # Applied -> No Response (hiring 15)
add_link(3, 6, 4, network_color)    # Applied -> Screener (network 4)
add_link(3, 6, 15, hiring_color)    # Applied -> Screener (hiring 15)

# Screener -> Rejected by Screen, Full Round
add_link(6, 7, 1, network_color)    # Screener -> Rejected by Screen (network 1)
add_link(6, 7, 5, hiring_color)     # Screener -> Rejected by Screen (hiring 5)
add_link(6, 8, 3, network_color)    # Screener -> Full Round (network 3)
add_link(6, 8, 10, hiring_color)    # Screener -> Full Round (hiring 10)

# Full Round -> Rejected by Panel, Offer
add_link(8, 9, 1, network_color)    # Full Round -> Rejected by Panel (network 1)
add_link(8, 9, 7, hiring_color)     # Full Round -> Rejected by Panel (hiring 7)
add_link(8, 10, 2, network_color)   # Full Round -> Offer (network 2)
add_link(8, 10, 3, hiring_color)    # Full Round -> Offer (hiring 3)

# Offer -> Accepted, Declined
add_link(10, 11, 1, network_color)  # Offer -> Accepted (network 1)
add_link(10, 12, 1, network_color)  # Offer -> Declined (network 1)
add_link(10, 12, 3, hiring_color)   # Offer -> Declined (hiring 3)

# Sanity check
assert len(sources) == len(targets) == len(values) == len(link_colors)

# Node colors (visual guidance)
node_colors = [
    "rgba(31,119,180,0.9)",   # Network
    "rgba(255,127,14,0.9)",   # Hiring.cafe
    "rgba(220,220,220,0.9)",  # Abandoned Lead
    "rgba(200,200,200,0.9)",  # Applied
    "rgba(220,180,180,0.9)",  # Rejected
    "rgba(200,200,220,0.9)",  # No Response
    "rgba(200,220,200,0.9)",  # Screener
    "rgba(255,200,200,0.9)",  # Rejected by Screen
    "rgba(210,210,255,0.9)",  # Full Round
    "rgba(240,200,220,0.9)",  # Rejected by Panel
    "rgba(200,255,200,0.9)",  # Offer
    "rgba(140,255,140,0.9)",  # Accepted
    "rgba(255,140,140,0.9)"   # Declined
]

fig = go.Figure(data=[go.Sankey(
    node=dict(
        pad=18,
        thickness=18,
        line=dict(color="black", width=0.5),
        label=labels,
        color=node_colors
    ),
    link=dict(
        source=sources,
        target=targets,
        value=values,
        color=link_colors,
        hovertemplate='%{source.label} → %{target.label}: %{value}<extra></extra>'
    )
)])

fig.update_layout(
    title_text="Hiring funnel Sankey — direct source flows (no Leads node)",
    font_size=12,
    height=700,
    margin=dict(l=20, r=20, t=60, b=20)
)

fig.show()

# To save as interactive HTML:
# fig.write_html("sankey_hiring_funnel_direct.html", include_plotlyjs='cdn')

Couldn't be bothered to write this by hand for just an online comment. There's enough that can be improved with this, but I think it's ok to show how it can be done quite easily.

  • source
  • parent
  • hideshow 2 child comments