You have one indicator on the chart that plots something useful, say a smoothed momentum line or a volatility ratio, and now you want a second script to read that line and do more with it. Maybe you want to smooth it again, draw a band around it, or color the background when it crosses a level. In Pine Script v6 the tool for this is input.source, and it is one of the least understood inputs because it quietly does two jobs at once.
This guide covers both jobs. First the everyday one, where input.source lets a user switch a script between close, hl2, volume and the other built-in series. Then the less obvious one, where the same dropdown lets you pick a plot from a different indicator on the chart and feed it into your own calculations. You will see the exact syntax, the limits that surprise people, and complete scripts you can paste into the TradingView Pine Editor.
What input.source actually returns
input.source adds a dropdown to a script's settings dialog. Its return type is a series of float, which means the value changes on every bar, exactly like close does. That is the whole reason it exists. Most inputs in Pine Script, such as input.int or input.float, return a single fixed value that stays the same for the whole run. A source input returns a full series of numbers, one per bar, so you can pass it straight into functions like ta.ema, ta.rsi or ta.highest that expect a series.
The signature is short. The first argument is the default value, and it has to be one of the built-in price series: open, high, low, close, hl2, hlc3, ohlc4, hlcc4, or a volume or time series such as volume. Then come the optional title, tooltip, inline, group and display arguments, which work the same way they do on every other input function. You can read the full list in the input types guide if you want the rest of the family side by side.
//@version=6
indicator("Smoothed Source", overlay = false)
src = input.source(close, "Source", tooltip = "Pick a price series or the plot of another indicator")
len = input.int(14, "Length", minval = 1)
smooth = ta.ema(src, len)
plot(smooth, "Smoothed", color = color.teal, linewidth = 2)Add this to a chart and open its settings. The Source dropdown lists the built-in series. If you pick hl2 the line is recalculated on the midpoint of each bar instead of the close. Nothing in the code changed, and that is the point: the script is now written against "some series" rather than against close in particular.
The second job: reading another indicator's plot
Here is the part most tutorials skip. When other indicators are on the same chart, the Source dropdown does not only list the built-ins. It also lists the plots of those indicators, usually shown as the indicator name followed by the plot name. Choose one and your script receives that plot's values, bar by bar, as if it were a built-in series.
This is how you chain indicators without copying code between them. To see it work you need two scripts. The first one is a producer, an indicator whose only job is to plot a number.
//@version=6
indicator("Producer: Range Percent", overlay = false)
len = input.int(20, "Length", minval = 1)
avgRange = ta.sma(high - low, len)
avgClose = ta.sma(close, len)
rangePct = avgClose != 0 ? avgRange / avgClose * 100 : na
plot(rangePct, "Range Percent", color = color.orange)Add the producer to the chart first. Then add a consumer, which is any script that contains an input.source. The consumer below smooths whatever you point it at and shades the background while the value sits above its own average.
//@version=6
indicator("Consumer: Source Smoother", overlay = false)
src = input.source(close, "Source")
len = input.int(10, "Smoothing length", minval = 1)
avg = ta.sma(src, len)
above = not na(src) and not na(avg) and src > avg
plot(src, "Source", color = color.gray)
plot(avg, "Average", color = color.blue)
bgcolor(above ? color.new(color.green, 88) : na)Open the consumer's settings and change Source from Close to the producer's Range Percent plot. The gray line now follows the producer, the blue line is its ten bar average, and the background shading follows the relationship between the two. The consumer never needed to know how the producer computes anything. If you edit the producer's length later, the consumer follows automatically.
Why a default of close still matters
You might wonder why the dropdown needs a default at all if the user is going to choose something else. The answer is that the script has to run before anyone has picked anything. When you add the consumer to a chart for the first time, it uses the default, which is always a built-in series. It is also the series the script falls back on whenever the chosen plot is not available, for example when the producer has been removed from the chart.
That is worth planning for. Treat the source as something that can be missing or empty, and write the consumer so that a gap produces a visible empty line rather than a confusing error further down.
Guard against na from the producer
A producer rarely has a value on every bar. Moving averages need a warm-up period, and many indicators return na for their first bars. Whatever the producer sends, the consumer receives, including those gaps. Pine Script propagates na through arithmetic without raising an error, so an unguarded consumer can go blank in a way that looks like a bug in the wrong script. The na handling guide explains the mechanics in detail, and the short version applies here directly.
Check the input before you use it, and decide what the consumer should do when the check fails. Here the script uses nz for a plotted fallback and keeps the logical test separate so it never treats a gap as a zero.
//@version=6
indicator("Guarded Consumer", overlay = false)
src = input.source(close, "Source")
len = input.int(14, "Length", minval = 1)
hasValue = not na(src)
basis = ta.sma(src, len)
dev = ta.stdev(src, len)
upper = basis + dev * 2
lower = basis - dev * 2
plot(hasValue ? basis : na, "Basis", color = color.blue)
plot(hasValue ? upper : na, "Upper", color = color.red)
plot(hasValue ? lower : na, "Lower", color = color.green)The band here is the standard deviation envelope you may know from Bollinger Bands, but built on any source instead of only on the close. Point it at an oscillator and you get bands around the oscillator. Point it at volume and you get a volume envelope. The code does not change.
Several sources in one script
Nothing limits a script to one source input. A common pattern is two sources, one for the fast side of a calculation and one for the slow side. Give each a clear title and put them in the same group so the settings dialog stays readable.
//@version=6
indicator("Two Source Spread", overlay = false)
fastSrc = input.source(close, "Fast source", group = "Sources", inline = "src")
slowSrc = input.source(hl2, "Slow source", group = "Sources", inline = "src")
fastLen = input.int(8, "Fast length", minval = 1, group = "Lengths", inline = "len")
slowLen = input.int(21, "Slow length", minval = 1, group = "Lengths", inline = "len")
fast = ta.ema(fastSrc, fastLen)
slow = ta.ema(slowSrc, slowLen)
spread = fast - slow
plot(spread, "Spread", style = plot.style_columns, color = spread >= 0 ? color.teal : color.maroon)
hline(0, "Zero", color = color.gray)The inline argument places the two dropdowns on one row of the settings dialog. That keeps a script with many inputs from turning into a long scrolling list, which matters more than it sounds once you reuse the script across several charts.
The limits that catch people
Chaining through input.source is powerful, but a handful of rules decide whether it works, and they are rarely stated in one place.
First, the producer must be on the same chart. The dropdown only offers plots from scripts currently loaded on that chart, and the producer has to actually plot the value with plot(). A variable that is calculated but never plotted is invisible to the consumer.
Second, the consumer gets plotted values, not internal state. If the producer plots a rounded or rescaled version of a number, that is what arrives. Anything the producer calculates but does not plot, such as an array of pivots or a drawn label, cannot cross the boundary. For richer data sharing, a library of exported functions is the better tool, covered in the libraries guide.
Third, the default has to be a built-in series. You cannot hand input.source a computed expression like ta.sma(close, 10) as its default. If you want a smoothed default, take the raw source from the input and smooth it inside the script, as the examples above do.
Fourth, the result is a series, so it cannot be used where Pine Script demands a simple or constant value. A length argument, for instance, must be a simple integer, so you cannot derive it from a source. The type system guide explains the qualifiers and why these errors read the way they do.
Repainting travels downstream
When a consumer reads a producer, it inherits the producer's behavior. If the producer repaints, because it uses a pivot that needs future bars to confirm or a higher timeframe value that changes during the bar, the consumer will repaint too, and nothing in the consumer's own code will show you why. The consumer sees finished numbers and has no way to know which ones were provisional.
So before you chain anything, check how the producer behaves on live bars. Watch it on a one minute chart for a few minutes and see whether the last value jumps around before the bar closes. If it does, any condition you build on top is built on a moving target. The repainting guide lists the five common causes and how to spot each one, and it is a good checklist to run through before you trust a chained setup.
Choosing between input.source and a library
Both approaches share logic, but they suit different jobs. A source input is right when the user should decide, at runtime, which series feeds the calculation, and when the data is a plotted line that already exists on the chart. It needs no coding in the producer beyond a plot() call, and a user can swap the source in seconds without editing code.
A library is right when you need to share a calculation rather than a result, when several scripts should compute the same thing identically, or when the logic returns something that is not a single plotted line. The cost is that libraries have to be published and imported, and the importing script depends on a specific version. For a quick chain of two indicators, input.source is the lighter option. For a toolkit you plan to maintain, a library is.
Wiring a chain with the AI editor
The part of this workflow that slows people down is rarely the Pine Script itself. It is remembering the parameter names, keeping the defaults sensible, and getting the producer and consumer to agree. You can describe the pair to PineScripter's AI editor in plain English, for example "an indicator that takes any source and draws a standard deviation band around its moving average, with the source as a dropdown". It writes Pine Script v6 with the input.source already in place, checks the code for compile errors the way TradingView does, and fixes any it finds. When you later ask for a change, it edits only the affected lines instead of rewriting the script.
PineScripter's Chart will run the consumer on real crypto market data using its default source so you can see the lines before you paste it. Choosing another indicator's plot from the dropdown is something you do afterwards, inside TradingView, with the producer loaded on the same chart. Moving between the two like that is quicker than going back and forth with a general chatbot about error messages.
A short checklist before you ship a source input
Give the source a plain title, because users scan the settings dialog quickly. Pick a default that makes the script useful on its own, usually close. Test the script with at least three different sources, including volume and another indicator's plot, because a calculation that only makes sense on prices will produce odd numbers on anything else. Guard against na, since producers often start late. And write down, in the tooltip, what kind of value the script expects, so a user does not feed a script built for prices with an oscillator that sits between zero and one hundred without realizing the scale has changed.
That last point deserves attention. A band built with a fixed multiplier of the standard deviation adapts to scale, but a fixed threshold such as "above 70" does not. When you build on a source that could be anything, prefer relative measures over absolute levels, or expose the level as a separate input the user can adjust. For smoothing choices, the moving average types guide shows how SMA, EMA, RMA and WMA behave differently on the same data, which matters when the source is noisy.
Where to go from here
You now have both halves of input.source: the dropdown that makes a script independent of close, and the connection that lets one indicator consume another's plotted output. Start with the first example on your own chart, build a producer and consumer pair next, and read the limits section again if the dropdown does not show the plot you expect. Remember that everything here is about writing code that behaves as intended. It says nothing about whether any rule built on top of it is worth following, and that question belongs to testing with the Strategy Tester and your own judgment.
PineScripter is a coding tool, not a financial advisor. Nothing here is investment advice, and past behavior of any script does not predict future results.
Frequently asked questions
Can input.source read a plot from another indicator?
Yes. When another script is on the same chart and draws a value with plot(), that plot appears in the Source dropdown of your script's settings. Pick it and your script receives those values bar by bar.
What can I use as the default value of input.source?
A built-in series such as close, open, high, low, hl2, hlc3, ohlc4, hlcc4 or volume. A computed expression like ta.sma(close, 10) is not accepted as the default, so smooth the source inside the script instead.
Why does my script go blank when I choose another indicator's plot?
Most likely the producer returns na for its first bars, and na propagates through arithmetic. Check the source with not na(src) and decide what the script should do on those bars.
Will a script that reads another plot repaint?
It inherits the producer's behavior. If the producer repaints on live bars, the consumer sees those changing values too, so check the producer before chaining anything on top of it.
When should I use a library instead of input.source?
Use a library when you want to share a calculation or return something other than one plotted line. Use input.source when the user should pick an existing plotted series at runtime.
Describe your indicator in plain English and get Pine Script that compiles →
Disclaimer: PineScripter is a coding tool for Pine Script development. It does not provide financial advice and does not guarantee trading profits. Always backtest strategies thoroughly and understand the risks before live trading.