A Data Scientist at Nexxen plays a pivotal role in driving the intelligence behind one of the world's leading programmatic advertising platforms. Working across the Supply-Side Platform (SSP), Demand-Side Platform (DSP), and unified data management systems, data scientists here solve complex optimization problems at an immense scale. Every day, the platform processes billions of real-time ad queries, requiring sophisticated machine learning models to predict user behavior, optimize bidding strategies, and maximize publisher yield.
In this role, you will design, deploy, and scale machine learning pipelines that directly impact company revenue and partner ROI. The work is highly quantitative and sits at the intersection of auction theory, predictive modeling, and big data engineering. You will collaborate closely with product managers and platform engineers to translate massive streams of transactional data into actionable, automated algorithms that run in milliseconds.
For a senior-level position, Nexxen expects you to bring not only deep technical expertise but also the strategic vision to guide projects from conceptualization to production. The environment is fast-paced and highly dynamic, making it an exceptionally rewarding place for data scientists who thrive on solving high-throughput, low-latency engineering challenges.
Recruiter Screen
reportedMost candidates lose this call inside the first two minutes, during the walkthrough of their own background. The account runs chronologically, sits at the level of tools and titles, and never arrives at a decision anyone could have disagreed with. Anchor on a problem instead of a timeline: what the team could not answer, what you did about it, what happened next. Ninety seconds is enough, and stopping on time leaves room for the half of the call that belongs to you. What you ask about how work gets prioritised signals your level more reliably than the walkthrough does.
What to demonstrate
- Whether your background summary has a shape (problem, decision, consequence) or is a chronological list of tools and employers
- Whether you can account for gaps, short stints and the reason you are looking, unprompted and without hedging
- The substance of the questions you ask back, which an experienced screener reads as a level signal
How to prepare
- Time your opening walkthrough against a clock. If it runs past two minutes, compress the earliest role into a single clause and spend the recovered time on the most recent one
- Write one honest sentence for every gap or short stint visible on your resume and offer it before being asked about it
- Prepare questions about how work arrives and gets prioritised: who writes the request, how often priorities change, and what happens to an analysis after it is delivered
Technical Screening
reportedThis round decides whether someone can hand you a schema and a question and trust the number that comes back. Correctness under a clock is the bar, not clever syntax. The habit that separates strong from weak answers is checking the grain: after every join, know how many rows you expect and whether the count moved. Most wrong answers in this format are not wrong logic, they are a fan-out from a key that turned out not to be unique, or a filter applied before an aggregate when it belonged after. Say what you expect before you run it.
What to demonstrate
- Whether your row counts survive each join, and whether you notice on your own when they do not
- Deliberate handling of rows that fail to match, including whether the question needs an inner join or a left join with the non-matches kept and counted
- Whether NULLs are treated on purpose, given that a NULL compares equal to nothing and that COUNT of a column skips it
- Reaching a defensible answer inside the window instead of a refined one after it
How to prepare
- Take a two-table schema, write a join that fans out on purpose, then fix it by collapsing the many-side to one row per key before joining. Repeat until the fix is reflex rather than recall.
- Write a funnel as one query and print the distinct user count at each stage, then confirm each stage is a subset of the one above it rather than assuming it
- Do a few timed runs in a plain text box with no autocomplete and no formatter, since assessment editors often have neither
Virtual Onsite Loop
reportedWhere a loop includes a partner from outside the data team, that conversation usually carries the same weight as the technical ones and gets the least preparation. The person opposite you will not follow a derivation and does not need to. They are working out whether having you involved would make their decisions better or slower. The failure mode is not being too technical. It is answering a question about a decision with a description of your method, leaving the translation to them. What they carry into the debrief is the sentence you handed them, not the analysis underneath it.
What to demonstrate
- Whether a statistical result arrives as something the partner could act on, with the one caveat that would change their decision kept and the rest left out
- Whether you can state what you need from their side, in their terms: instrumentation that does not exist yet, a definition they own, or a holdout they have to agree to
- Whether uncertainty is given as a range someone can plan against, rather than as hedging that invites them to ignore the result
- Whether you ask what decision is actually on the table before explaining anything
How to prepare
- Take a result you know well and write the version for someone who stops reading after one sentence, then the three-minute version, and check the short one is not the long one with the qualifications stripped out
- For a past project, list everything you asked a non-technical partner for and how you phrased it, then rewrite each ask so it names what goes unmeasured without it
- Practise saying where a result does not apply, out loud, in one sentence that a partner could repeat accurately to someone else
PracHub editorial advice for the preparation topics above.
Comparing conversion rates between users who were exposed to an ad and users who were not.
Exposure is the output of a targeting and bidding system that ranks users by predicted conversion propensity, so the exposed group has a higher baseline conversion rate before the ad renders. The measured difference therefore estimates the quality of the targeting model, not the effect of the advertising, and it is biased upward by an amount that grows as the model gets better. The valid control is the set of users the system would have shown the ad to but deliberately did not, captured through a ghost-bid or public-service-announcement holdout that records auction wins without serving the advertiser's creative. Anyone who proposes matching or covariate adjustment to fix this should be asked what unobserved feature the bidder used that the matching model does not have.
Randomising users into treatment and control while both arms draw from the same campaign budget.
The arms compete in the same auctions and against the same budget, so treatment winning more impressions directly starves control, and the measured gap includes that cannibalisation rather than only the ad effect. The test looks methodologically clean, the randomisation is genuinely valid, and the lift is still partly manufactured. This is an interference violation, not a randomisation failure, so checking balance on covariates will not catch it. The fixes are to randomise at a unit that contains the budget, such as a geographic market, or to give each arm its own budget and its own pacing, and then be explicit that you are now comparing two separately-budgeted campaigns.
Crediting a treatment for regression to the mean
Selecting a group because it is extreme (lowest-engagement users, accounts having their worst month, the bottom decile of a score) moves that group's expected next-period value back toward the average even under no treatment, by exactly as much as the selecting measure is imperfectly correlated with its own later value. Compare against units that met the same selection rule and went untreated, or use two pre-periods so the bounce-back is visible before the intervention starts. A pre-post number on a group chosen for being extreme measures the selection rule, not the treatment.
Reporting a p-value with no effect size or interval
Give the estimated difference with a confidence interval in the units the business cares about, then say whether that whole interval is worth acting on. A p-value only addresses whether you can rule out exactly zero; it says nothing about magnitude.
Choose a category, try a prompt, then open its approach, worked solution or follow-up when you need it.
Check predicted conversion-rate calibration with a reliability table
scored has 4 million rows at bid_request_log grain for one campaign: predicted_cvr, win_flag, and converted, which is observed only where win_flag is true and a conversion landed within 7 days. The win rate is about 2% and the conversion rate among won impressions about 0.4%. Without using a library calibration helper, build a 20-bin equal-frequency reliability table with bin count, mean predicted_cvr, observed rate and an interval around it, then compute count-weighted expected calibration error. Say whether the model is miscalibrated, in which direction, and over which population your answer holds.
Approach
- Restrict to win_flag == True and state the precondition plainly: converted is only defined where the ad served, so the table measures calibration on the won slice. That is the population the advertiser pays for, but it is selected by the bid and the auction, so the result cannot be extended to no-bid or lost opportunities where the prediction is never tested.
- Bin with equal frequency (pd.qcut with duplicates='drop'), not equal width. Prediction distributions in this setting are heavily right-skewed with point masses, so equal-width bins put most of the mass in one bin and leave the tail bins with too few conversions to say anything. Report how many bins survived if edges collapsed.
- Per bin compute n, mean predicted_cvr, observed rate, and a Wilson score interval. At a 0.4% base rate the normal approximation produces negative lower bounds and understates uncertainty in the low bins, so the interval choice is not cosmetic here.
- Compute ECE as the count-weighted mean of |observed - predicted| across bins, and report it next to the base rate: 0.002 of absolute error is small against a 5% base rate and enormous against 0.4%.
- Read the direction from the sign pattern rather than the scalar. Observed below predicted across the top bins is head over-prediction, typically from training on a differently-selected population or from scoring against a conversion window that has not matured; a flat observed rate across rising predictions means the score has little ranking power in this range, which is a different problem from miscalibration.
Worked solution 25 min
- Subset to won rows, record n_won and the observed base rate, and confirm converted has no nulls within that subset.
- bins = pd.qcut(predicted_cvr, 20, labels=False, duplicates='drop'); report the realised bin count.
- groupby(bins).agg(n, pred_mean, obs_rate), then compute Wilson bounds elementwise from n and obs_rate at z = 1.96.
- ece = ((n / n.sum()) * (obs_rate - pred_mean).abs()).sum(); print it alongside the base rate and the ratio of the two.
Follow-up
- The pooled curve looks calibrated but ctv supply is badly off. How do you test for segment-level miscalibration without fishing across dozens of cuts?
- The model retrains daily while conversions take up to 7 days to land. What does that do to the head of the reliability curve, and in which direction?
- How would you turn this diagnostic into a bid correction, and what would you verify before shipping it?
Detect duplicate conversion reports across pixel and server sources
You are given a pandas DataFrame conversions holding raw conversion_event rows: conversion_id, advertiser_id, conversion_ts, received_ts, conversion_type, conversion_value_usd, order_id, device_id, click_tracking_id, source, dedup_key. The is_duplicate column has been removed because producing it is the task. Roughly 30% of rows carry a null dedup_key. Return a boolean Series aligned to the input index marking duplicate reports of one real-world conversion, plus a per-advertiser table giving the duplication rate and the dedup_key coverage behind it. State your keying rule and its fallbacks.
Approach
- Declare a keying ladder before writing code and apply the tiers in priority order so each row is matched by exactly one rule: tier 1 (advertiser_id, dedup_key) where dedup_key is present, tier 2 (advertiser_id, order_id) where it is not, tier 3 a bounded behavioural rule. Keep the tier label on the output so the result is auditable rather than a bare boolean.
- Within tier 1, sort by received_ts then conversion_id and mark every row after the first in a group. Keeping the earliest-received row is the right survivor because it is the one already counted in published numbers; keeping the latest silently restates history every time a late report lands.
- For tier 3, sort within (advertiser_id, device_id, conversion_value_usd) by conversion_ts and collapse rows whose gap to the current survivor is under 60 seconds, carrying the survivor forward rather than chaining diffs. A plain diff chain collapses a run of rows 40 seconds apart into one, which is a different and wrong rule.
- Implement tiers 1 and 2 with sort plus groupby.cumcount, never with a self-join: a self-join on advertiser_id is quadratic in the largest advertiser and will not finish on a real month of data. Tier 3 cannot be written that way. Because a flagged row does not become the survivor, each comparison depends on which earlier rows were already collapsed, so cumcount (which flags every row after the first regardless of gap) and a shifted-diff (which compares against the previous row, not the survivor) both compute a different rule. Run tier 3 as one sequential O(n) pass over the sorted arrays - a Python loop over the numpy columns, or numba if the tier is large - which is affordable because tier 3 holds only the rows with neither dedup_key nor order_id.
- Report duplication rate alongside dedup_key coverage per advertiser. Coverage is what makes the rate interpretable: at 30% nulls the measured duplication rate is a lower bound, and the gap is an advertiser tagging problem, not a conversion problem.
Follow-up
- Tier 3 will collapse two genuine purchases of the same item a minute apart. How do you bound that false-positive rate, and for a CPA report would you rather over-collapse or under-collapse?
- An advertiser populates dedup_key with order_id on browser_pixel rows and with a session id on server_api rows. What does your ladder do, and how would you detect that from the data alone?
- If the duplication rate is 8%, what is the effect on attributed CPA, and in which direction does it move the number the advertiser sees?
Implement click-through rate and eCPM from written definitions
Two frames. impressions: impression_id, served_ts, line_item_id, creative_id, billed_price_micros_usd, is_billable, viewability_status, ivt_status. clicks: click_id, impression_id (nullable), click_ts, line_item_id, ivt_status, is_billable. Implement exactly these definitions: click-through rate is valid clicks whose parent impression is billable and valid, over billable valid impressions, with both sides bucketed on the parent impression's served_ts UTC date; eCPM is SUM(billed_price_micros_usd)/1e6 over billable impressions divided by their count over 1000, same bucketing. Return one row per (line_item_id, served_date) with impressions, clicks, ctr and ecpm_usd, plus a count of every row you dropped and why.
Approach
- Filter impressions to is_billable and ivt_status == 'valid' once, and treat that frame as the single source of the denominator for both metrics. Deriving everything from one filtered population is what guarantees the two metrics describe the same impressions.
- Join clicks into that filtered frame on impression_id from the click side, keeping only matched rows, because the definition conditions the numerator on the parent impression being billable and valid. Count unmatched clicks separately and split them into null impression_id (orphan beacons) and non-null but filtered-out parents, since a rising orphan share is a measurement fault rather than a CTR movement.
- Take served_ts from the impression side after the join and never click_ts. Bucketing on click_ts puts a click in a different day bucket from its own impression, which distorts both days for any cohort near midnight.
- Decide the click fan-out rule explicitly: one impression can carry more than one click row, so either deduplicate to one click per impression or state that you are counting click events. Without that decision CTR is not bounded by 1.
- Aggregate the filtered impressions by (line_item_id, served_date) for count and summed micros, aggregate matched clicks on the same key, then outer-join and fill missing click counts with zero so zero-click line-item days survive instead of disappearing from the output.
Follow-up
- One impression has two click rows. Does your CTR exceed 1.0, and which definition would you put on an advertiser-facing report?
- How does the answer change if the denominator becomes measured-viewable impressions rather than all valid billable impressions?
- A filter change removed the cheapest 10% of inventory and eCPM rose 12%. How do you present that so nobody reads it as a price increase?
Daily effective CPM per line item from billable impressions
ad_impression has impression_id, served_ts TIMESTAMPTZ, line_item_id, billed_price_micros_usd BIGINT, is_billable BOOLEAN, ivt_status TEXT (valid, givt, sivt) and currency_code. billed_price_micros_usd is the amount charged for that single impression, in USD micros. Write one query returning, per line_item_id and per UTC calendar day over a supplied date range, the billable impression count, total spend in USD, and effective CPM meaning spend per thousand impressions. Count only rows with is_billable = TRUE and ivt_status = 'valid'. Order by day, then spend descending.
Approach
- Apply the two filters positively rather than by exclusion: is_billable = TRUE AND ivt_status = 'valid'. Writing ivt_status <> 'givt' silently keeps the sophisticated-invalid rows, which is the larger and later-arriving category.
- Bucket with (served_ts AT TIME ZONE 'UTC')::date rather than date_trunc('day', served_ts). date_trunc on a TIMESTAMPTZ resolves in the session's TimeZone setting, so the same query returns different day boundaries for two analysts on the same warehouse.
- Aggregate once: COUNT(*) and SUM(billed_price_micros_usd) grouped by line item and day. Everything else is arithmetic on those two columns.
- Collapse the unit conversion into a single divisor. Micros to USD is a division by 1e6, per-thousand is a multiplication by 1000, so eCPM = SUM(billed_price_micros_usd) / (1000.0 * COUNT(*)). Use numeric literals so a BIGINT sum is not divided with integer arithmetic.
- Return the impression count in the output, not just the rate. eCPM rises mechanically whenever cheap inventory is filtered out, so the rate is uninterpretable without the volume beside it.
Worked solution 15 min
- Count rows before and after the is_billable and ivt_status filters and note the drop; it is usually a few percent, and a sudden change in that drop is itself the finding.
- Bucket the day as (served_ts AT TIME ZONE 'UTC')::date so the result does not depend on anyone's session timezone.
- Group by (line_item_id, day) and emit COUNT(*) AS impressions and SUM(billed_price_micros_usd) AS micros.
- Derive spend_usd = micros / 1e6 and ecpm_usd = micros / (1000.0 * impressions) in an outer select over that aggregate.
- Order by day then spend_usd descending, and reconcile the top row against a line item whose spend you already know.
Follow-up
- eCPM rose 12% week over week while spend was flat. What are the candidate causes, and which column separates a price change from a mix shift?
- How do you compute a period-level eCPM across 30 days, and why is the mean of the 30 daily eCPMs a different number?
- currency_code is not always USD. What does billed_price_micros_usd mean on those rows, and what would you need before the sum is trustworthy?
Attributed cost per action without double counting spend or credit
attribution_credit holds one row per (conversion_id, touchpoint_id, attribution_model, model_version), with touchpoint_ts, line_item_id, credit_fraction, credited_value_usd and click_window_days, the model's click lookback in whole days, which is constant within one (attribution_model, model_version) pair; credit_fraction sums to 1.0 across a conversion's touchpoints within one model and one version. ad_impression has line_item_id, served_ts, billed_price_micros_usd and is_billable. For a UTC date range, return per line_item_id and day: spend, attributed conversions, attributed CPA, attributed ROAS, and a maturity flag derived from the model's own click window, for one named attribution_model and model_version. Both sides must land in the same daily buckets. State which timestamp each side is bucketed on and why.
Approach
- Pin attribution_model AND model_version before aggregating anything. The table stores several models, and several versions of each, for the same conversion. An unfiltered SUM(credit_fraction) therefore reports conversions multiplied by the number of (model, version) pairs present, which is usually a clean integer multiple and so survives a sanity glance.
- Bucket credit on touchpoint_ts, never on conversion_ts. Spend is incurred when the impression served, so aligning the outcome to the touchpoint puts numerator and denominator on the same cohort. Bucketing on conversion_ts shifts every conversion forward by a variable lag and produces day-over-day CPA swings that are pure bucketing artefacts and cannot be corrected downstream.
- Aggregate the two sides in separate CTEs at their own grain, then FULL OUTER JOIN on (line_item_id, day). Joining ad_impression to attribution_credit directly matches each impression against every credit row that references it and multiplies spend by the path count.
- Use a full outer join deliberately: a day with spend and no credit is a genuine CPA of infinity worth surfacing, and a day with credit and no spend means the touchpoint predates the spend window, which is a signal about window choice rather than a row to discard.
- Attributed conversions is SUM(credit_fraction), a fractional quantity, not COUNT(*). Counting rows credits one conversion once per touchpoint and inflates the total by the mean path length, which makes CPA look far better than it is.
- Flag recent days as immature. Spend is final within hours while credit keeps arriving for the model's click_window_days plus ingestion lag, so the most recent click_window_days plus roughly two days have CPA biased high and ROAS biased low. Read that window off the filtered rows rather than hard-coding a number: click_window_days is constant within a pinned (attribution_model, model_version), so MAX(click_window_days) over the pinned filter is a read of that constant. Verify the precondition first, because if MIN and MAX differ the column is not constant, the flag is being computed against a window that does not exist, and it has to come from the model configuration instead.
Follow-up
- Last Tuesday's CPA improved 15% overnight with no change in delivery. What happened, and what would you have shipped to prevent the question?
- The same conversion has credit rows under last_click and under data_driven. Can you sum them? What do you give a client who wants one number?
- model_version changed on the 14th. How do you present a series that spans that boundary without implying a performance change?
Cut the variance of a market-level holdout with pre-period data
A 28-day holdout randomises 80 geo_dma markets 40/40; treated markets run the campaign and held-out markets get no delivery. The outcome is deduplicated conversion_event rows per market over the flight plus a 7-day window. Market sizes are heavily skewed and the unadjusted design detects only a 12% relative lift at 80% power. Twelve months of pre-period market conversions are available. Specify a variance-reduction plan, state the precision you expect, and state what would disqualify a covariate.
Approach
- Apply CUPED: define Y_adj = Y - theta*(X - mean(X)) where X is pre-period conversions for the same market and theta = Cov(Y,X)/Var(X), estimated on the pooled arms. Variance falls by a factor of (1 - rho^2), where rho is the correlation between pre-period and in-period outcomes.
- Estimate rho from history before the test runs, by regressing a past 28-day market window on its own preceding pre-period covariate. At rho = 0.9 the variance multiplier is 0.19, the standard error multiplier is 0.436, and the 12% MDE falls to roughly 5.2%.
- Disqualify any covariate measured at or after assignment. In-flight impressions, in-flight spend and in-flight clicks are all downstream of treatment; adjusting on them shifts the point estimate rather than only shrinking its variance.
- Stratify as well as adjust: form matched pairs on pre-period conversion volume, randomise within pair, and then analyse with pair fixed effects or a paired difference. Pairing that is not carried into the estimator buys nothing at all.
- Handle the skew at design time by analysing the ratio metric, conversions per thousand eligible bid requests, or by weighting on pre-period volume, and commit to the choice before seeing the arms.
- Pre-register theta's estimation rule and the covariate window, so neither can be tuned after the outcome becomes visible.
Follow-up
- CUPED moves the point estimate by 30% of its own standard error. What do you conclude?
- Would you use pre-period conversions or pre-period spend as the covariate, and why?
- How would the plan change if only 20 markets were available?
Decide whether a 50.4 to 49.6 arm split is chance
A 7-day two-arm test assigns devices to arm A or arm B by hash of device_id, intended 50/50. Counting distinct device_id in ad_impression, arm A has 1,204,338 devices and arm B has 1,186,902. The hash function is unit-tested and uniform. State whether this split is consistent with fair 50/50 assignment, show the test you use, and give the two mechanisms in a bidding system most likely to produce exactly this kind of imbalance.
Approach
- Run a chi-square goodness-of-fit against the intended ratio on the randomisation unit: expected 1,195,620 per arm, so chi-square = 2 * 8718^2 / 1,195,620 = 127 on 1 degree of freedom. At this sample size a 0.36 percentage-point deviation is not noise.
- Notice the count was taken on ad_impression, which is a post-treatment population: a device only appears there once it has been served. The assignment population is the set of devices that entered an auction the line item was eligible for, and that lives in bid_request_log.
- Re-run the same test on distinct device_id in bid_request_log. A 50/50 split there with a skew in ad_impression localises the problem to differential delivery rather than broken randomisation.
- Enumerate the mechanisms that make one arm's devices less likely to be logged: one creative losing more auctions on price or format (win_flag), asymmetric no_bid_reason rates such as brand_safety or frequency_capped, and bid requests with NULL device_id falling into a non-uniform fallback bucket.
- Do not read the treatment effect until the mechanism is identified. An imbalance this size invalidates the comparison regardless of how well covariates balance, because the filter that produced it is plausibly correlated with the outcome.
Worked solution 15 min
- Expected per arm = (1,204,338 + 1,186,902) / 2 = 1,195,620, so each arm deviates by 8,718.
- chi-square = 2 * 8718^2 / 1,195,620 = 2 * 63.57 = 127.1 on 1 degree of freedom.
- Compare with the 3.84 critical value: p is on the order of 2e-29, so a fair split is rejected decisively.
- Repeat the count on bid_request_log distinct device_id per arm, and again restricted to response_status = 'bid', to find the funnel step where the split first diverges.
Follow-up
- The split on bid_request_log is also 50.4/49.6. What do you check next?
- What share of bid requests carry a NULL device_id on each supply source, and how would that alone manufacture a sample ratio mismatch?
- If the mechanism turns out to be one creative timing out more often, is any part of the test salvageable?
One advertiser's conversions doubled the week their SDK shipped
An advertiser's daily conversion_event rows roughly doubled starting 14 August, with no change in their order volume as they report it. That week they added a server_api feed alongside their existing browser_pixel. conversion_event has conversion_id, advertiser_id, conversion_ts, received_ts, conversion_type, order_id, device_id, user_id_hash, click_tracking_id, source, dedup_key and is_duplicate, where is_duplicate is written by our dedup job. Quantify the true conversion count, name the failure precisely, and state what you would tell the account team.
Approach
- Compare row counts against distinct dedup_key counts per advertiser per day. If rows double while distinct keys stay flat, the extra rows are duplicates that the dedup job never collapsed, and the real conversion level never moved.
- Establish why the job failed rather than that it failed: compute the null rate of dedup_key by source, and for non-null keys compare the value format between browser_pixel and server_api on the same order_id. Case, prefixing and whitespace differences are the usual cause and are invisible in a count of non-null keys.
- Use order_id as an independent second key. Distinct order_id per advertiser per day that is flat across 14 August confirms the real outcome count is unchanged and gives you the recovery rule.
- Size the blast radius downstream: duplicated conversions inflate attributed conversions, deflate CPA and inflate ROAS for every line item serving that advertiser, and the attribution_credit rows already written carry the inflation.
- Write the restatement rather than just the diagnosis — which advertiser, which dates, the direction and size of the correction, and whether any optimisation decision was already taken on the inflated numbers.
Follow-up
- The advertiser cannot change their server payload for a quarter. What dedup rule would you run in the meantime, and what does it get wrong?
- How would you detect this class of failure automatically for the other several thousand advertisers?
- If the two sources disagree on conversion_value_usd for the same order, which one wins and why?
Roughly 90 minutes a night on weekdays with one longer weekend block. The plan deliberately cuts scope rather than compressing everything, on the assumption that finishing one thing a night beats half-starting four.
Prepare, practise & reflect
One practical outcome each day. Spend longer where you need it.
0 / 7 done01Fix the scope and set a baseline
- Read the role description and write the three things the loop will almost certainly test, then write an explicit not-doing list for everything else and keep it visible all week.
- Take one 20-minute SQL prompt and one 10-minute metric question cold, and write the single sentence that says what blocked each attempt, since that sentence is what decides which two topics get the most evenings.
- Set the week's one rule: one problem finished to completion every night, including the night you only have 40 minutes.
Deliverable: A one-page scope with an explicit not-doing list and two cold attempts, each carrying one sentence on what blocked it.
Practice prompt ↗Practice prompt ↗Worked solution ↗02One query pattern, written three times
- Choose the single pattern most likely to appear (a cohort retention grid, or a funnel counted by user) and write it three times from a blank file rather than editing the previous attempt.
- On the third attempt, write the grain of every CTE as a comment before writing its body.
- Stop at 90 minutes even if the third version is imperfect, and write the one thing you would fix with another hour.
Deliverable: Three independent versions of the same query plus a note on what changed between them.
Practice prompt ↗Practice prompt ↗03Only the statistics you will be asked to defend
- Write, in under 200 words, how you would decide whether a difference between two groups is real: the test, its assumptions, and what you would switch to when an assumption fails.
- Compute a 95 percent confidence interval for a difference in proportions by hand on realistic numbers, then write in one sentence what changes if the two samples are paired rather than independent.
- Write your answer to "what does a p-value mean", check it against a definition, and delete the version that describes it as the probability the hypothesis is true.
Deliverable: A 200-word written answer and one hand-computed interval you can reproduce under pressure.
Practice prompt ↗Practice prompt ↗04One case, and the assumptions holding it up
- Answer one product case aloud in 20 minutes with a recording running, then listen back with a pen and mark every claim you asserted without saying what it rested on: an assumed user behaviour, an assumed data source, an assumed baseline rate, an assumed grain.
- Pick the three assumptions the recommendation actually depends on, write how you would check each one against data, and say which one being wrong would flip the recommendation rather than merely weaken it.
- Write the four-step structure you used onto a card small enough to hold in working memory when you are nervous.
Deliverable: One recording, three load-bearing assumptions each with a written check, and a four-step structure card.
Practice prompt ↗Practice prompt ↗Worked solution ↗05Your own work, timed
- Write a 90-second version and a four-minute version of your main project, and time both out loud rather than reading them.
- Prepare answers to the two follow-ups that always come: what you would do differently, and how you knew it worked.
- Put one number in the first sentence and be able to say exactly where that number came from and what it excludes.
Deliverable: Two timed narratives with one defensible number in the opening line.
Practice prompt ↗06The one full rehearsal, in a longer weekend block
- Run a 60-minute mock covering query work, a case and a behavioural question in a single sitting with no breaks, because sustained attention is the thing evenings have not trained.
- Immediately afterwards, and before hearing any feedback, write the three moments you lost the thread.
- Spend the rest of the block only on those three moments, and on nothing you merely feel shaky about.
Deliverable: Mock notes naming three failure moments with a specific fix written under each.
Practice prompt ↗07Taper
- Write the 20-minute warm-up you will actually do on the morning of the interview: one query you can already write from a blank file, one metric you can define out loud, and nothing you have never seen before.
- Re-read only your own notes from this week, and open no new material.
- Write down the logistics: the tool you will be asked to work in, whether lookups are allowed, and the sentence you will use when you do not know something.
Deliverable: A one-page card holding the case structure, the project numbers, and the logistics.
Practice prompt ↗Worked solution ↗Expand any day for tasks and deliverables. Your progress is saved on this device.
Have two ready. In one, the data was on your side and you had to move someone who outranked you. In the other, the pushback was correct and you changed position. The second is the harder story and it lands better, because it shows you separate being right from being attached to an answer. Name the person's actual objection.
Correcting a published CPA win that was window maturation
Three weeks ago you published a note saying a bid-strategy migration cut attributed CPA by 18%. A colleague points out that you compared the first seven days after migration against a fully matured pre-period, while conversions for the recent dates were still arriving. Recomputed at equal maturity the improvement is 3%, inside noise. The note has been quoted in a quarterly business review deck. Deliverable: what you do in the next 24 hours, what you write and to whom, and the structural change that prevents a repeat.
Approach
- The interviewer is probing sequencing under embarrassment, so establish the corrected magnitude before writing anything: recompute both periods restricted to conversions received within the same number of days after conversion_ts, so a frozen window is compared to a frozen window.
- Build the account's maturation curve from received_ts minus conversion_ts, reporting the share of a click-day's eventual conversions landed by day 1, 3, 7 and 14. It both explains the error and becomes the artefact that prevents the next one.
- Enumerate the decisions taken since publication that cited the 18%: budget moved, line items paused, the deck slide, any advertiser-facing claim. Cost each one, because the correction's urgency is set by what was acted on, not by how wrong the number was.
- Send one message, not a drip, with the corrected number in the first sentence, the affected dates, the direction of the error, and an explicit statement of which decisions it does and does not reverse. Notify whoever presents the deck first.
- Ship the guard: a freeze rule in the query or dashboard so no period is reportable until click_window_days plus observed ingestion lag have elapsed, with immature dates badged rather than hidden.
Follow-up
- The corrected number had gone the other way and the migration looked better than you published. Does anything about your response change?
- How do you decide whether this warrants a written postmortem or a one-line correction?
Claiming impact for three projects with honest counterfactuals
You are writing a performance self-review. Over two quarters you shipped a bid-shading recalibration, a rewrite of the click-through-rate query that fixed an invalid-traffic filter applied to only one side of the ratio, and an incrementality test that led to a line item being paused. Deliverable: for each, the number you would claim, the counterfactual you claim it against, and the portion of credit that belongs to someone else. One of the three has no defensible dollar figure. Say which, and what you claim instead.
Approach
- The interviewer is probing whether you apply the same causal standard to your own work that you apply to an advertiser's, so write the counterfactual for each claim before the number: what would the metric have been over the same period without this work?
- For the shading recalibration, compare clearing price and profit on won impressions at matched supply mix across exchange_id, ad_format, device_type and geo_country, and report the profit change rather than the win-rate change; under first-price clearing a higher win rate can accompany worse profit.
- For the query fix, claim the magnitude of the bias removed rather than a revenue number: the gap between the old rate, which filtered invalid traffic on the numerator only, and the corrected symmetric rate, plus the decision that was being made on the wrong figure.
- For the incrementality test, claim the decision, not the savings. The paused budget's fate was never measured, so any dollar figure would assume that money vanished rather than moved. This is the item with no defensible number.
- Name specific collaborators and what they contributed, and pre-empt the obvious challenge by stating the confound you know about, such as seasonality or supply mix drift, and the bound you put on it.
Follow-up
- Your manager points out the paused line item's spend simply moved to another line item. Does your claimed impact survive?
- How do you claim credit for work whose value is a bad decision that did not happen?
Ranking three teams' requests against one sprint of capacity
You have three requests and capacity for roughly one and a half. The supply team wants eligible-RPM impact sizing for a floor-price change shipping in two weeks. An advertiser team wants a pacing diagnosis for a $400k line item delivering at 60% of budget. The invalid-traffic team wants help validating a new sophisticated-invalid-traffic classifier before it restates last quarter. Deliverable: your ranking with the reason for each, exactly what you say to the two teams you deprioritise, and the trigger that would reorder the list.
Approach
- The interviewer is probing whether you rank on decision structure or on social pressure, so attach two attributes to each request before ranking: the date the decision is actually made, and how expensive it is to reverse afterwards. Seniority of the requester is not one of the inputs.
- Look for the request that can be collapsed rather than sequenced. The pacing diagnosis is usually a single grouped query over bid_request_log by no_bid_reason and response_status per hour for that line_item_id; time-boxed to two hours it stops competing for the sprint at all.
- Size the other two in revenue at risk per week so the ranking is arguable rather than asserted: the floor change's expected eligible-RPM delta against the spend it touches, and the invoiced spend inside the period the classifier would restate.
- Rank on irreversibility where deadlines are close together. A classifier that restates already-invoiced periods is the hardest of the three to unwind once shipped, which can outrank a nearer deadline.
- Deprioritise with a date and a fallback rather than an apology: name what you will not do, when you could, the smallest thing you can give them now, and who else could take it.
Follow-up
- The underdelivering advertiser escalates to your director. What actually changes in your plan, and what do you refuse to change?
- How do you stop the pacing question arriving fresh every sprint?
- 01
Three weeks ago you published a note saying a bid-strategy migration cut attributed CPA by 18%. A colleague points out that you compared the first seven days after migration against a fully matured pre-period, while conversions for the recent dates were still arriving. Recomputed at equal maturity the improvement is 3%, inside noise. The note has been quoted in a quarterly business review deck. Deliverable: what you do in the next 24 hours, what you write and to whom, and the structural change that prevents a repeat.
- 02
You are writing a performance self-review. Over two quarters you shipped a bid-shading recalibration, a rewrite of the click-through-rate query that fixed an invalid-traffic filter applied to only one side of the ratio, and an incrementality test that led to a line item being paused. Deliverable: for each, the number you would claim, the counterfactual you claim it against, and the portion of credit that belongs to someone else. One of the three has no defensible dollar figure. Say which, and what you claim instead.
- 03
You have three requests and capacity for roughly one and a half. The supply team wants eligible-RPM impact sizing for a floor-price change shipping in two weeks. An advertiser team wants a pacing diagnosis for a $400k line item delivering at 60% of budget. The invalid-traffic team wants help validating a new sophisticated-invalid-traffic classifier before it restates last quarter. Deliverable: your ranking with the reason for each, exactly what you say to the two teams you deprioritise, and the trigger that would reorder the list.
Is this an official Nexxen interview guide?
No. It is PracHub's own research and practice material for the Data Scientist role at Nexxen. Rounds and questions reflect what candidates have reported, not a process Nexxen has published, and they change over time. Confirm the current format and scope with your recruiter.
PracHub interview research ↗How technical is the interview process for this role?
The process is highly technical and rigorous. You should expect to be evaluated on live coding, SQL proficiency, machine learning theory, and system design, even during rounds that may initially be described as behavioral or conversational.
PracHub interview research ↗How should I handle a passive or quiet interviewer during the process?
If you encounter an interviewer with a passive communication style, take the initiative to drive the conversation. Proactively walk through your resume, explain the architecture of your key projects, and highlight the business impact of your work in a structured manner.
PracHub interview research ↗What technologies does the Nexxen data science team use most frequently?
The team primarily utilizes Python, SQL, and Spark for data processing and model development. They leverage modern cloud infrastructure and containerization tools to deploy and scale their machine learning pipelines.
PracHub interview research ↗Sources & methodology 3 sources ↗
No official company page is cited. Rounds and questions come from candidate reports and PracHub editorial material; each source shows the date it was read.
- 01PracHub interview research ↗
PracHub editorial research into this company and role, maintained with this guide. Candidate-reported, not an employer publication.
PracHub page · Accessed 2026-09-22 - 02PracHub Data Scientist practice ↗
Cross-company practice questions for this role.
PracHub page · Accessed 2026-09-22 - 03PracHub interview preparation framework ↗
The framework the preparation plan follows.
PracHub page · Accessed 2026-09-22