Get image filepath and variables from a shader node


I am looking for a method to read various variables from a shader node from within my python script.

In order to get for instance a texture map filepath from the BSDF I use something like:

                if (Material):
                    bsdf_node = Material.node_tree.nodes.get('Principled BSDF')
                    if (bsdf_node):
                            link = node.links[0]
                            link_node = link.from_node
                            texture =
                            print("[%s] no diffuse texture set."%(,True,False)

This works fine, and I extended the program for various other inputs of the BSDF shader. My problem is that I try to extract the same information from a connected normal map. In other words I would like to:

  1. find the connected ‘Normal Map’ node
  2. save the normal map strength to a variable
  3. find the connected ‘Image’ node, which will hold the normal map
  4. Extract the filename from the image node.

Of course, I could use Material.node_tree.nodes.get(‘Normal Map’), however I would like to make sure that I am dealing with a node that is connected to my Principled BSDF node.

I can’t really figure out how to navigate from node to node and hope you could give me pointers.


Access the link through the node’s sockets.

node_tree.nodes['Principled BSDF'].inputs['Normal'].links

Thanks for the reply!
I think I begin to understand the correlations. I got this now:

# 1. this gets me the normal input of the BSDF node:
n_normal = bsdf_node.inputs.get('Normal')
# 2. this gets me the color input of the Normal Map node:
n_normal_map = n_normal.links[0].from_node.inputs.get('Color')
# 3. this is the link between the input node of the normal map and the image texture node:
link = n_normal_map.links[0]
# 4. this gets me the filename of the texture node:
texture =

Additionally, in my addon, I wrap every crucial part into try-except blocks, to catch missing nodes - similar to my first example above.
Is this good practice, or am I missing something?

And then there’s part 2: how do I get the “strength” float value from the normal map?

# 4. this gets me the filename of the texture node:
texture =

No, that’s getting you the name of the image datablock being referenced by the image node. You shouldn’t assume it’ll always match the filename.

You can easily check the attributes of a particular node by:

  • Hovering over the relevant UI element with python tooltips enabled
  • Using autocomplete in the python terminal
  • Using dir on the datablock

Whaaaaaaaaaaaaaaaaat? That is amazing! I had no idea this was a thing!. Thank you!

OK, I’ll keep that in mind.